/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #ifndef _DAI_AGGR_INSTANCE_COMMON_H #define _DAI_AGGR_INSTANCE_COMMON_H #include "OdPlatformSettings.h" #include "OdaCommon.h" #include "daiBuildOptions.h" #include "daiAggr/daiAggr.h" #include "daiAggr/daiIterator.h" #include "daiAggrBaseInstance.h" #include "daiAggr/daiCollectionWrapper.h" #include "daiUtils/daiUnset.h" #include "daiUtils/daiCustomCompare.h" #include "daiSelect.h" #include "daiEnum.h" #include "daiBinary.h" #include "daiObjectSDAI.h" #include "TD_PackPush.h" //DOM-IGNORE-BEGIN template struct has_value_type { private: template static typename T1::value_type test(int); template static void test(...); public: enum { value = !std::is_void(0))>::value }; }; namespace OdDAI { class BaseType; namespace Utils { DAI_EXPORT bool extractUniqueOption(const OdDAI::AggregationType* aggregationType); } template inline bool cantBeAddedDuringRead(const TItem& testVAlue) { return OdDAI::Utils::isUnset(testVAlue) != false; } template<> inline bool cantBeAddedDuringRead(const OdDAI::Binary& /*testVAlue*/) { // Add exception for binary type, we had a problem during textures reading. // Empty binary in texture is a black color. return false; } template class Tsmartptr, class TItem> inline bool cantBeAddedDuringRead(const Tsmartptr& testVAlue) { return testVAlue.isNull() == false; } template inline bool uniqueCompare(const TItem& leftValue, const TItem& rightValue) { return OdDAI::compare::isEqual(leftValue, rightValue) && OdDAI::Utils::isUnset(leftValue) != true && OdDAI::Utils::isUnset(rightValue) != true; } using OdDAIObjectSDAIPtrRow = OdDAI::OdDAIObjectSDAI*; template<> inline bool uniqueCompare(const OdDAIObjectSDAIPtrRow& leftValue, const OdDAIObjectSDAIPtrRow& rightValue) { if (leftValue == rightValue) { return true; } if (leftValue == nullptr || rightValue == nullptr) { return false; } return leftValue->id() == rightValue->id(); } template class TPtr, class TItem> inline bool uniqueCompare(const TPtr& leftValue, const TPtr& rightValue) { return leftValue == rightValue && leftValue.isNull() != true && leftValue.isNull() != true; } template class DAI_EXPORT AggrInstanceCommonBase : public AggrInstance { public: using item_type = TItem; using value_type = TItem; const OdRxValueType& type() const override { return OdRxValueType::Desc::value(); } void onBeforeRead() override { } void onAfterRead(bool /*readSucceeded*/) override { } int getMemberCount() const override { return static_cast(m_itemCollection.size()); } virtual bool isMember(const OdRxValue& itemToCheck) const ODRX_OVERRIDE { TItem transitValue; if (itemToCheck >> transitValue == false) { return false; } return isMember(transitValue); } virtual bool isMember(const TItem& itemToCheck) const { return m_itemCollection.isContains(itemToCheck); } bool checkValuesUniqueness () const override { const OdArray& itemsCollection = m_itemCollection.getCollection(); for (OdUInt32 leftIndex = 0; leftIndex < itemsCollection.length(); ++leftIndex) { const auto& leftValue = itemsCollection[leftIndex]; auto rightIndex = leftIndex + 1; for (; rightIndex < itemsCollection.length(); ++rightIndex) { const auto& rightValue = itemsCollection[rightIndex]; if (uniqueCompare(leftValue, rightValue)) { return false; } } } return true; } int hasValue(int startIndex, const OdRxValue& itemToFound) const override { TItem transitValue; if (itemToFound >> transitValue == false) { return false; } return hasValue(startIndex, transitValue); } int hasValue(int startIndex, const TItem& itemToFound) const { unsigned int foundIndex = 0; if (m_itemCollection.getCollection().find(itemToFound, foundIndex, startIndex)) { return static_cast(foundIndex); } return -1; } void copyFrom(const AggrInstance* from) override { if (!from || from == this) { return; } const AggrInstanceCommonBase* other = dynamic_cast*>(from); if (!other) { return; } setArray(other->getArray()); } virtual TItem generateAggrItem() const { return Utils::getUnset(); } bool compareTo(const AggrInstance* to) const override { if (to == this) { return true; } const AggrInstanceCommonBase* other = dynamic_cast*>(to); return other && OdDAI::compare::isEqual(getArray(), other->getArray()); } const OdArray& getArray() const { return m_itemCollection.getCollection(); } virtual void checkArrayBeforeSet(const OdArray& /*newArray*/){} virtual void setArray(const OdArray& newArray) { checkArrayBeforeSet(newArray); m_itemCollection.setCollection(newArray); } virtual bool read(IAggrReader& aggrReader); bool write(IAggrWriter& aggrWriter); protected: AggrInstanceCommonBase() { } const OdDAI::AggregationType* extractInternalAggrType() const override { return nullptr; } virtual bool forseAddItemDuringRead() const { return false; } protected: CollectionWrapper m_itemCollection; }; } namespace OdDAI { template class DAI_EXPORT AggrInstanceCommon : public AggrInstanceCommonBase { public: template bool copyToArray(OdArray& copyTo) const { copyTo = this->m_itemCollection.getCollection(); return true; } template bool copyFromArray(OdArray& copyFrom) { this->m_itemCollection.setCollection(copyFrom); return true; } protected: AggrInstanceCommon() { } }; } template::value> class TypeDetect; template class TypeDetect { public: using value_type = ValueToPut; }; template class TypeDetect { public: using value_type = OdDAI::Aggr*; }; namespace OdDAI { template<> class DAI_EXPORT AggrInstanceCommon : public AggrInstanceCommonBase { public: virtual void setArray(const OdArray& arrayFrom); template bool copyToArray(OdArray& copyTo) const { copyTo.reserve(m_itemCollection.size()); TOtherItem templateItem; for (auto& itemFrom : m_itemCollection.getCollection()) { if (itemFrom == nullptr) { continue; } copyTo.push_back(templateItem); TOtherItem& lastOdArray = copyTo.last(); if (!itemFrom->getArrayValues::value_type, typename TOtherItem::value_type>(lastOdArray)) { return false; } } return true; } template bool copyFromArray(OdArray& copyFrom) { m_itemCollection.clear(); for (auto& copyItem : copyFrom) { auto newAggrItem = generateAggrItem(); newAggrItem->setArrayValues::value_type, typename TOtherItem::value_type>(copyItem); m_itemCollection.pushBackValue(newAggrItem); } if (aggrType() == aggrTypeArray) { auto ordered = orderedLogic(); auto arraySize = ordered != nullptr ? static_cast(ordered->getUpperBound() - ordered->getLowerBound()) : getMemberCount(); while (m_itemCollection.size() <= arraySize) { m_itemCollection.pushBackValue(nullptr); } } return true; } protected: AggrInstanceCommon(){} }; } namespace OdDAI { template inline bool AggrInstanceCommonBase::read(IAggrReader& aggrReader) { if (!aggrReader.skipUntil('(')) throw OdError(eSyntaxError); if (aggrReader.skipUntilRet(')')) return true; // Empty aggregate, but not unset! bool isForceAddItem = forseAddItemDuringRead(); { TItem val = generateAggrItem(); if (eOk != aggrReader.read(val, false)) { itemCleaner(val); throw OdError(eSyntaxError); } if (isForceAddItem == true || cantBeAddedDuringRead(val) == false) { m_itemCollection.pushBackValue(val); } else { itemCleaner(val); } } if (aggrReader.skipUntilRet(')')) return true; while (true) { TItem val = generateAggrItem(); if (aggrReader.read(val, true) != eOk) { itemCleaner(val); break; } if (isForceAddItem == true || cantBeAddedDuringRead(val) == false) { m_itemCollection.pushBackValue(val); } else { itemCleaner(val); } if (aggrReader.skipUntilRet(')')) break; } return true; } namespace{ template bool shouldBeSkippedDuringStreamWrite(const TElement& element) { return false; } template<> bool shouldBeSkippedDuringStreamWrite(const OdDAIObjectId& element) { return element.isErased(); } } template bool AggrInstanceCommonBase::write(IAggrWriter& aggrWriter) { aggrWriter.wrChar('('); char delimeter = 0; const auto& collectionToWrite = m_itemCollection.getCollection(); for (const auto& valueToWrite : collectionToWrite) { if (shouldBeSkippedDuringStreamWrite(valueToWrite)) { continue; } if (delimeter) { aggrWriter.wrChar(delimeter); } else { delimeter = ','; } aggrWriter.wrPrimitive(*const_cast(&valueToWrite)); } aggrWriter.wrChar(')'); return true; } } //DOM-IGNORE-END #include "TD_PackPop.h" #endif // _DAI_AGGR_H