File indexing completed on 2024-04-14 05:45:44

0001 /*
0002     This file is part of the Okteta Core library, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #ifndef OKTETA_ARRAYCHANGEMETRICS_HPP
0010 #define OKTETA_ARRAYCHANGEMETRICS_HPP
0011 
0012 // lib
0013 #include "oktetacore_export.hpp"
0014 #include "size.hpp"
0015 #include "address.hpp"
0016 // Qt
0017 #include <QDataStream>
0018 
0019 namespace Okteta {
0020 
0021 // TODO: do we need the invalid status?
0022 class OKTETACORE_EXPORT ArrayChangeMetrics
0023 {
0024     friend QDataStream& operator<<(QDataStream& outStream, const ArrayChangeMetrics& metrics);
0025     friend QDataStream& operator>>(QDataStream& inStream, ArrayChangeMetrics& metrics);
0026 
0027 private:
0028     static constexpr Address InvalidAddress = -1;
0029 
0030 public:
0031     enum Type
0032     {
0033         // Insertion,
0034         // Removal,
0035         Replacement,
0036         Swapping,
0037         // Filling,
0038         // Setting,
0039         Invalid
0040     };
0041 
0042 public:
0043     static constexpr ArrayChangeMetrics asReplacement(Address offset, Size removeLength, Size insertLength);
0044     static constexpr ArrayChangeMetrics asSwapping(Address firstOffset, Address secondOffset, Size secondLength);
0045 
0046 public:
0047     ArrayChangeMetrics() = default;
0048     ArrayChangeMetrics(const ArrayChangeMetrics&) = default;
0049     constexpr ArrayChangeMetrics(Type type, Address offset, qint32 secondArgument, qint32 thirdArgument);
0050 
0051     ~ArrayChangeMetrics() = default;
0052 
0053     ArrayChangeMetrics& operator=(const ArrayChangeMetrics&) = default;
0054 
0055 public:
0056     constexpr bool operator==(const ArrayChangeMetrics& other) const;
0057 
0058 public:
0059     void revert();
0060 
0061 public:
0062     constexpr int type() const;
0063     constexpr Address offset() const;
0064     constexpr bool isValid() const;
0065 
0066 public: // Replacement properties
0067     constexpr Size removeLength() const;
0068     constexpr Size insertLength() const;
0069     constexpr Size lengthChange() const;
0070 
0071 public: // Swapping properties
0072     constexpr Size firstLength() const;
0073     constexpr Address secondStart() const;
0074     constexpr Address secondEnd() const;
0075     constexpr Size secondLength() const;
0076 
0077 private:
0078     Type mType = Invalid;
0079     Address mOffset = InvalidAddress;
0080     // TODO: how to make the arguments of the size of the largest union member?
0081     union
0082     {
0083         qint32 mSecondArgument = 0;
0084         Size mRemoveLength;
0085         Address mSecondStart;
0086     };
0087     union
0088     {
0089         qint32 mThirdArgument = 0;
0090         Size mInsertLength;
0091         Size mSecondLength;
0092     };
0093 };
0094 
0095 inline constexpr ArrayChangeMetrics ArrayChangeMetrics::asReplacement(Address offset, Size removeLength, Size insertLength)
0096 {
0097     return {Replacement, offset, removeLength, insertLength};
0098 }
0099 
0100 inline constexpr ArrayChangeMetrics ArrayChangeMetrics::asSwapping(Address firstOffset, Address secondOffset, Size secondLength)
0101 {
0102     return
0103         Q_ASSERT(firstOffset < secondOffset),
0104         ArrayChangeMetrics{Swapping, firstOffset, secondOffset, secondLength};
0105 }
0106 
0107 inline constexpr ArrayChangeMetrics::ArrayChangeMetrics(Type type, Address offset, qint32 secondArgument, qint32 thirdArgument)
0108     : mType(type)
0109     , mOffset(offset)
0110     , mSecondArgument(secondArgument)
0111     , mThirdArgument(thirdArgument)
0112 {}
0113 inline constexpr bool ArrayChangeMetrics::operator==(const ArrayChangeMetrics& other) const
0114 {
0115     return mType == other.mType
0116            && mOffset == other.mOffset
0117            && mSecondArgument == other.mSecondArgument
0118            && mThirdArgument == other.mThirdArgument;
0119 }
0120 inline void ArrayChangeMetrics::revert()
0121 {
0122     if (mType == Replacement) {
0123         const Size helper = mInsertLength;
0124         mInsertLength = mRemoveLength;
0125         mRemoveLength = helper;
0126     } else if (mType == Swapping) {
0127         const Size oldSecondLength = mSecondLength;
0128         mSecondLength = firstLength();
0129         mSecondStart = mOffset + oldSecondLength;
0130     }
0131 }
0132 
0133 inline constexpr bool ArrayChangeMetrics::isValid()        const { return mOffset != InvalidAddress; }
0134 inline constexpr int ArrayChangeMetrics::type()            const { return mType; }
0135 inline constexpr Address ArrayChangeMetrics::offset()      const { return mOffset; }
0136 inline constexpr Size ArrayChangeMetrics::removeLength()   const { return mRemoveLength; }
0137 inline constexpr Size ArrayChangeMetrics::insertLength()   const { return mInsertLength; }
0138 inline constexpr Size ArrayChangeMetrics::lengthChange()   const { return mInsertLength - mRemoveLength; }
0139 inline constexpr Address ArrayChangeMetrics::secondStart() const { return mSecondStart; }
0140 inline constexpr Address ArrayChangeMetrics::secondEnd()   const { return mSecondStart + mSecondLength - 1; }
0141 inline constexpr Size ArrayChangeMetrics::firstLength()    const { return mSecondStart - mOffset; }
0142 inline constexpr Size ArrayChangeMetrics::secondLength()   const { return mSecondLength; }
0143 
0144 QDataStream& operator<<(QDataStream& outStream, const ArrayChangeMetrics& metrics);
0145 QDataStream& operator>>(QDataStream& inStream, ArrayChangeMetrics& metrics);
0146 
0147 inline QDataStream& operator<<(QDataStream& outStream, const ArrayChangeMetrics& metrics)
0148 {
0149     outStream << metrics.mType << metrics.mOffset << metrics.mSecondArgument << metrics.mThirdArgument;
0150     return outStream;
0151 }
0152 
0153 inline QDataStream& operator>>(QDataStream& inStream, ArrayChangeMetrics& metrics)
0154 {
0155     int type;
0156     inStream >> type >> metrics.mOffset >> metrics.mSecondArgument >> metrics.mThirdArgument;
0157     metrics.mType = (ArrayChangeMetrics::Type)type; // TODO: find out how to stream to enum directly
0158     return inStream;
0159 }
0160 
0161 }
0162 
0163 Q_DECLARE_TYPEINFO(Okteta::ArrayChangeMetrics, Q_MOVABLE_TYPE);
0164 
0165 #endif