Guest User

Untitled

a guest
Apr 9th, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.82 KB | None | 0 0
  1. #include <algorithm>
  2. #include <cassert>
  3. #include <cctype>
  4. #include <cstring>
  5. #include <optional>
  6. #include <stdexcept>
  7. #include <string>
  8. #include <string_view>
  9. #include <type_traits>
  10. #include <variant>
  11. #include <vector>
  12.  
  13. #include "adsData.h"
  14.  
  15. using namespace std::literals::string_literals;
  16. using namespace std::literals::string_view_literals;
  17.  
  18. AdsVarData::AdsVarData(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset, SizeType index = 0u - 1u)
  19.     : info_{info}, group_{group}, offset_{offset}, index_{index}
  20. {}
  21.  
  22. namespace
  23. {
  24.     std::string operator+(std::string lhs, std::string_view rhs)
  25.     {
  26.         return std::move(lhs.append(rhs.data(), rhs.size()));
  27.     }
  28.     std::string operator+(std::string_view lhs, std::string_view rhs)
  29.     {
  30.         std::string result;
  31.         result.reserve(lhs.size() + rhs.size());
  32.         result.assign(lhs.data(), lhs.size()).append(rhs);
  33.         return result;
  34.     }
  35.     using SizeType = AdsData::SizeType;
  36.  
  37.     inline bool icmp_less(std::string_view lhs, std::string_view rhs)
  38.     {
  39.         return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](auto x, auto y) {
  40.             return x == '\0'
  41.                        ? y != '\0'
  42.                        : y == '\0' ? false : x == '.' ? y != '.' : y == '.' ? false : std::tolower(x) < std::tolower(y);
  43.         });
  44.     }
  45.     inline bool icmp_equal(std::string_view lhs, std::string_view rhs)
  46.     {
  47.         return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
  48.                           [](auto x, auto y) { return std::tolower(x) == std::tolower(y); });
  49.     }
  50.  
  51.     using adsDataCursor::AdsDataCursor;
  52.     using adsDataCursor::AdsTypeTag;
  53.     using adsDataCursor::DatatypeId;
  54.     using adsDataCursor::IdList;
  55.     using adsDataCursor::implicit_cast;
  56.     using adsDataCursor::LimitMode;
  57.  
  58.     template <LimitMode limitMode = LimitMode::byCount>
  59.     using DtCursor = AdsDataCursor<AdsTypeTag::datatypeEntry, limitMode, limitMode == LimitMode::bySize>;
  60.     template <LimitMode limitMode = LimitMode::byCount>
  61.     using SymCursor       = AdsDataCursor<AdsTypeTag::symbolEntry, limitMode, limitMode == LimitMode::bySize>;
  62.     using ArrayInfoCursor = AdsDataCursor<AdsTypeTag::datatypeArrayInfo, LimitMode::byCount, false>;
  63.  
  64.     using DtIds  = IdList<AdsTypeTag::datatypeEntry>;
  65.     using SymIds = IdList<AdsTypeTag::symbolEntry>;
  66.     using ArrIds = IdList<AdsTypeTag::datatypeArrayInfo>;
  67. } // namespace
  68.  
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. class AdsData::SubSymbolInfo
  71. {
  72. public:
  73.     SubSymbolInfo(std::string_view name, std::string_view comment, SizeType offset, bool isStatic, bool isBit,
  74.                   AdsData::DatatypeInfo* typeData = nullptr)
  75.         : name(name), comment(comment), offset(offset), isStatic(isStatic), isBit(isBit), typeData(typeData)
  76.     {}
  77.     std::string            name;
  78.     std::string            comment;
  79.     SizeType               offset;
  80.     bool                   isStatic;
  81.     bool                   isBit;
  82.     AdsData::DatatypeInfo* typeData;
  83.  
  84.     friend bool operator==(const SubSymbolInfo& lhs, const SubSymbolInfo& rhs)
  85.     {
  86.         return icmp_equal(lhs.name, rhs.name);
  87.     }
  88.     friend bool operator==(const SubSymbolInfo& lhs, std::string_view rhs) { return icmp_equal(lhs.name, rhs); }
  89.     friend bool operator==(std::string_view lhs, const SubSymbolInfo& rhs) { return icmp_equal(lhs, rhs.name); }
  90. };
  91.  
  92. class AdsData::SymbolInfo
  93. {
  94. public:
  95.     SubSymbolInfo baseInfo;
  96.     SizeType      group;
  97.  
  98.     SymbolInfo(const SymCursor<>& sym, DatatypeInfo* typeData)
  99.         : baseInfo(sym.get<SymIds::name>(), sym.get<SymIds::comment>(), sym.get<SymIds::offset>(),
  100.                    sym.get<SymIds::isStatic>(), sym.get<SymIds::isBitValue>(), typeData),
  101.           group(sym.get<SymIds::group>())
  102.     {}
  103.  
  104.     friend bool operator<(const SymbolInfo& lhs, const SymbolInfo& rhs)
  105.     {
  106.         return icmp_less(lhs.baseInfo.name, rhs.baseInfo.name);
  107.     }
  108.     friend bool operator<(const SymbolInfo& lhs, std::string_view rhs) { return icmp_less(lhs.baseInfo.name, rhs); }
  109.     friend bool operator<(std::string_view lhs, const SymbolInfo& rhs) { return icmp_less(lhs, rhs.baseInfo.name); }
  110. };
  111.  
  112. class AdsData::ArrayInfo : public SubSymbolInfo
  113. {
  114.     struct AdsDatatypeArrayInfo
  115.     {
  116.         constexpr AdsDatatypeArrayInfo(const ArrayInfoCursor& cursor)
  117.             : lBound(cursor.get<ArrIds::lBound>()), elements(cursor.get<ArrIds::elements>())
  118.         {}
  119.         std::uint32_t lBound;
  120.         std::uint32_t elements;
  121.     };
  122.  
  123.     std::vector<AdsDatatypeArrayInfo> arrayInfoData_;
  124.     SizeType                          numElements_;
  125.  
  126. public:
  127.     explicit ArrayInfo(const DtCursor<>& dt)
  128.         : AdsData::SubSymbolInfo(""sv, dt.get<DtIds::comment>(), 0, false, false), arrayInfoData_{}, numElements_{1}
  129.     {
  130.         auto arrayInfoData = dt.get<DtIds::arrayInfoData>();
  131.         auto arraySize     = dt.get<DtIds::size>();
  132.         assert(arrayInfoData.count() != 0);
  133.         arrayInfoData_.reserve(arrayInfoData.count());
  134.         for (; arrayInfoData; ++arrayInfoData)
  135.         {
  136.             auto&    info   = arrayInfoData_.emplace_back(arrayInfoData);
  137.             SizeType rBound = info.lBound + info.elements - 1;
  138.             ADSDATACURSOR_VERIFY("%1%\narray info corrupted with\ninfo.elements == %2%\ninfo.lBound == %3%\nrBound == "
  139.                                  "%4%\narraySize == %5%",
  140.                                  info.elements != 0 && rBound >= info.lBound && arraySize % info.elements == 0,
  141.                                  info.elements, info.lBound, rBound, arraySize);
  142.             arraySize /= info.elements;
  143.             numElements_ *= info.elements;
  144.         }
  145.     }
  146.     SizeType index(std::string_view i) const
  147.     {
  148.         auto     workIndex = i;
  149.         SizeType realIndex = 0;
  150.         for (auto& info : arrayInfoData_)
  151.         {
  152.             auto pos = workIndex.find(',');
  153.             if ((&info == &arrayInfoData_.back()) != (pos == workIndex.npos))
  154.                 throw std::out_of_range("index with wrong number of dimensions: "s + i);
  155.             auto curIndex = workIndex;
  156.             if (pos != workIndex.npos)
  157.             {
  158.                 curIndex.remove_suffix(curIndex.size() - pos);
  159.                 workIndex.remove_prefix(pos + 1);
  160.             }
  161.             auto n = svtoi(curIndex);
  162.             if (n < info.lBound || n - info.lBound >= info.elements)
  163.                 throw std::out_of_range("index out of range: "s + i);
  164.             // we don't need to check for overflow here since the constructor already ensures that
  165.             // indizes stay within proper bounds
  166.             realIndex = realIndex * info.elements + (n - info.lBound);
  167.         }
  168.         return realIndex;
  169.     }
  170.     std::string toString(SizeType i) const
  171.     {
  172.         if (i >= numElements_)
  173.             throw std::out_of_range("index out of range");
  174.         std::string result = "]";
  175.         for (auto it = arrayInfoData_.cend(); it != arrayInfoData_.cbegin();)
  176.         {
  177.             auto& info     = *--it;
  178.             auto  curIndex = i % info.elements + info.lBound;
  179.             i /= info.elements;
  180.             do
  181.             {
  182.                 result.push_back(static_cast<char>('0' + curIndex % 10));
  183.             } while (curIndex /= 10);
  184.             if (&info != &arrayInfoData_.front())
  185.                 result.push_back(',');
  186.         }
  187.         result.push_back('[');
  188.         std::reverse(result.begin(), result.end());
  189.         return result;
  190.     }
  191.     SizeType        elemSize() const noexcept;
  192.     SizeType        numElements() const noexcept { return numElements_; }
  193.     static SizeType svtoi(std::string_view s)
  194.     {
  195.         SizeType result = 0;
  196.         if (s.empty())
  197.             throw std::out_of_range("index corrupted");
  198.         for (; !s.empty(); s.remove_prefix(1))
  199.         {
  200.             if (s[0] < '0' || s[0] > '9')
  201.                 throw std::out_of_range("index corrupted");
  202.             auto curDigit = static_cast<unsigned char>(s[0] - '0');
  203.             if ((std::numeric_limits<SizeType>::max() - curDigit) / 10 < result)
  204.                 throw std::out_of_range("index corrupted");
  205.             result = result * 10 + curDigit;
  206.         }
  207.         return result;
  208.     }
  209. };
  210.  
  211. class AdsData::DatatypeInfo
  212. {
  213. public:
  214.     DatatypeInfo(std::string_view name, SizeType size, DatatypeId id) : name(name), size(size), id(id) {}
  215.     explicit DatatypeInfo(const DtCursor<>& dt)
  216.         : name(dt.get<DtIds::name>()), size(dt.get<DtIds::size>()), id(dt.get<DtIds::typeId>())
  217.     {
  218.         ADSDATACURSOR_VERIFY("%1%\nEntry must be either datatype or dataitem",
  219.                              dt.get<DtIds::isDatatype>() != dt.get<DtIds::isDataitem>());
  220.         ADSDATACURSOR_VERIFY("%1%\ndatatype cannot be both array and struct/union at the same time",
  221.                              !dt.get<DtIds::isDatatype>()
  222.                                  || (dt.get<DtIds::numArrayDims>() == 0 || dt.get<DtIds::numSubItems>() == 0));
  223.         ADSDATACURSOR_VERIFY("%1%\ndataitem cannot contain subelements",
  224.                              !dt.get<DtIds::isDataitem>()
  225.                                  || (dt.get<DtIds::numArrayDims>() == 0 && dt.get<DtIds::numSubItems>() == 0));
  226.  
  227.         if (dt.get<DtIds::numSubItems>() != 0)
  228.         {
  229.             auto& subs = typeSpecs.emplace<std::vector<SubSymbolInfo>>();
  230.             subs.reserve(dt.get<DtIds::numSubItems>());
  231.             for (auto sub = dt.get<DtIds::subItemData>(); sub; ++sub)
  232.             {
  233.                 ADSDATACURSOR_VERIFY("%1%\nsubElements must be dataitems", sub.get<DtIds::isDataitem>());
  234.                 subs.emplace_back(sub.get<DtIds::name>(), sub.get<DtIds::comment>(), sub.get<DtIds::offset>(),
  235.                                   sub.get<DtIds::isStatic>(), sub.get<DtIds::isBitValue>(), nullptr);
  236.             }
  237.         }
  238.         else if (dt.get<DtIds::numArrayDims>() != 0)
  239.         {
  240.             typeSpecs.emplace<ArrayInfo>(dt);
  241.         }
  242.         else if (!dt.get<DtIds::type>().empty())
  243.         {
  244.             typeSpecs.emplace<DatatypeInfo*>();
  245.         }
  246.         else
  247.         {
  248.             typeSpecs.emplace<std::monostate>();
  249.         }
  250.     }
  251.     std::string name;
  252.     SizeType    size;
  253.     DatatypeId  id;
  254.     bool        isPointer   = false;
  255.     bool        isReference = false;
  256.     bool        visited     = false; // used for cycle detection
  257.     enum
  258.     {
  259.         baseSpec,
  260.         compoundSpec,
  261.         arraySpec,
  262.         classSpec
  263.     };
  264.     std::variant<std::monostate, // base type
  265.                  DatatypeInfo*,  // compound type (alias or pointer)
  266.                  ArrayInfo,      // array
  267.                  std::vector<SubSymbolInfo>>
  268.         typeSpecs; // class
  269.  
  270.     friend bool operator<(const AdsData::DatatypeInfo& lhs, const AdsData::DatatypeInfo& rhs)
  271.     {
  272.         return lhs.name < rhs.name;
  273.     }
  274.     friend bool operator<(const AdsData::DatatypeInfo& lhs, std::string_view rhs) { return lhs.name < rhs; }
  275.     friend bool operator<(std::string_view lhs, const AdsData::DatatypeInfo& rhs) { return lhs == rhs.name; }
  276.     friend bool operator==(const AdsData::DatatypeInfo& lhs, const AdsData::DatatypeInfo& rhs)
  277.     {
  278.         return lhs.name == rhs.name;
  279.     }
  280.     friend bool operator==(const AdsData::DatatypeInfo& lhs, std::string_view rhs) { return lhs.name < rhs; }
  281.     friend bool operator==(std::string_view lhs, const AdsData::DatatypeInfo& rhs) { return lhs == rhs.name; }
  282. };
  283.  
  284. SizeType AdsData::ArrayInfo::elemSize() const noexcept { return typeData->size; }
  285.  
  286. namespace
  287. {
  288.     void cycleCheck(AdsData::DatatypeInfo* p)
  289.     {
  290.         ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: cycle detected", !p->visited);
  291.         p->visited                                                        = true;
  292.         static constexpr auto                                     deleter = [](auto* x) { x->visited = false; };
  293.         std::unique_ptr<AdsData::DatatypeInfo, decltype(deleter)> guard(p, deleter);
  294.         switch (p->typeSpecs.index())
  295.         {
  296.             default:
  297.                 assert(false);
  298.             case AdsData::DatatypeInfo::baseSpec:
  299.                 return;
  300.             case AdsData::DatatypeInfo::compoundSpec:
  301.                 if (!p->isPointer && !p->isReference)
  302.                     cycleCheck(std::get<AdsData::DatatypeInfo::compoundSpec>(p->typeSpecs));
  303.                 return;
  304.             case AdsData::DatatypeInfo::arraySpec:
  305.             {
  306.                 cycleCheck(std::get<AdsData::DatatypeInfo::arraySpec>(p->typeSpecs).typeData);
  307.                 return;
  308.             }
  309.             case AdsData::DatatypeInfo::classSpec:
  310.             {
  311.                 for (auto& sub : std::get<AdsData::DatatypeInfo::classSpec>(p->typeSpecs))
  312.                     cycleCheck(sub.typeData);
  313.                 return;
  314.             }
  315.         }
  316.     }
  317.  
  318.     const AdsData::DatatypeInfo* followAlias(const AdsData::DatatypeInfo* p) noexcept
  319.     {
  320.         while (p->typeSpecs.index() == AdsData::DatatypeInfo::compoundSpec && !p->isPointer && !p->isReference)
  321.             p = std::get<AdsData::DatatypeInfo::compoundSpec>(p->typeSpecs);
  322.         return p;
  323.     }
  324. } // namespace
  325.  
  326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  327. AdsData::AdsData() noexcept          = default;
  328. AdsData::AdsData(AdsData&&) noexcept = default;
  329. AdsData& AdsData::operator=(AdsData&&) noexcept = default;
  330.  
  331. AdsData::~AdsData() noexcept = default;
  332.  
  333. AdsData::AdsData(const std::vector<char>& symData, const std::vector<char>& dtData) : symbols_{}, types_{}
  334. {
  335.     // count how many datatype entries we have and verify their integrity
  336.     DtCursor<> allDts(&dtData[0], DtCursor<LimitMode::bySize>(&dtData[0], dtData.size()).size());
  337.  
  338.     // add to types_
  339.     types_.reserve(allDts.count());
  340.     for (auto& dt : allDts)
  341.         types_.emplace_back(dt);
  342.     std::sort(types_.begin(), types_.end());
  343.  
  344.     // TwinCAT2 doesn't send info about basic datatypes so we add them here as needed
  345.     // we don't link them yet, because adding to the types-vector might cause a reallocation,
  346.     // invalidating references in the process
  347.     for (auto& dt : allDts)
  348.     {
  349.         for (auto& sub : dt.get<DtIds::subItemData>())
  350.         {
  351.             ADSDATACURSOR_VERIFY("%1%\nstructure elements must have a type", !sub.get<DtIds::type>().empty());
  352.             auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
  353.             if (it == types_.end() || it->name != sub.get<DtIds::type>())
  354.                 types_.emplace(it, sub.get<DtIds::type>(), sub.get<DtIds::size>(), sub.get<DtIds::typeId>());
  355.         }
  356.         if (dt.get<DtIds::type>().empty())
  357.             continue; // base type or structure
  358.         auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
  359.         if (it == types_.end() || it->name != dt.get<DtIds::type>())
  360.         {
  361.             if (dt.get<DtIds::numArrayDims>() != 0)
  362.             {
  363.                 types_.emplace(it, dt.get<DtIds::type>(), dt.get<DtIds::size>() / ArrayInfo{dt}.numElements(),
  364.                                dt.get<DtIds::typeId>());
  365.             }
  366.             else
  367.             {
  368.                 types_.emplace(it, dt.get<DtIds::type>(), dt.get<DtIds::size>(), dt.get<DtIds::typeId>());
  369.             }
  370.         }
  371.     }
  372.  
  373.     // count how many symbol entries we have and verify their integrity
  374.     SymCursor<> allSyms(&symData[0], SymCursor<LimitMode::bySize>(&symData[0], symData.size()).size());
  375.  
  376.     // add base types as needed (TwinCAT2)
  377.     for (auto& sym : allSyms)
  378.     {
  379.         ADSDATACURSOR_VERIFY("%1%\nsymbols must have a type", !sym.get<SymIds::type>().empty());
  380.         auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
  381.         if (it == types_.end() || it->name != sym.get<SymIds::type>())
  382.             types_.emplace(it, sym.get<SymIds::type>(), sym.get<SymIds::size>(), sym.get<SymIds::typeId>());
  383.     }
  384.     // crosslink datatypes
  385.     for (auto& dt : allDts)
  386.     {
  387.         auto type = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::name>());
  388.         switch (type->typeSpecs.index())
  389.         {
  390.             default:
  391.                 assert(false);
  392.             case AdsData::DatatypeInfo::baseSpec:
  393.                 break;
  394.             case AdsData::DatatypeInfo::compoundSpec:
  395.             {
  396.                 auto                  it      = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
  397.                 static constexpr auto ptr_str = "POINTER TO "sv;
  398.                 static constexpr auto ref_str = "REFERENCE TO "sv;
  399.                 if (std::string_view{type->name}.compare(0, ptr_str.size(), ptr_str) == 0) // starts_with
  400.                     type->isPointer = true;
  401.                 else if (std::string_view{type->name}.compare(0, ref_str.size(), ref_str) == 0)
  402.                     type->isReference = true;
  403.                 ADSDATACURSOR_VERIFY("%1%", type->isPointer || type->isReference || dt.get<DtIds::size>() == it->size);
  404.                 std::get<AdsData::DatatypeInfo::compoundSpec>(type->typeSpecs) = &*it;
  405.                 break;
  406.             }
  407.             case AdsData::DatatypeInfo::arraySpec:
  408.             {
  409.                 auto  it   = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
  410.                 auto& info = std::get<AdsData::DatatypeInfo::arraySpec>(type->typeSpecs);
  411.                 ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched element size",
  412.                                      dt.get<DtIds::size>() / info.numElements() == it->size);
  413.                 info.typeData = &*it;
  414.                 break;
  415.             }
  416.             case AdsData::DatatypeInfo::classSpec:
  417.             {
  418.                 auto sub = dt.get<DtIds::subItemData>();
  419.                 for (auto& info : std::get<AdsData::DatatypeInfo::classSpec>(type->typeSpecs))
  420.                 {
  421.                     auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
  422.                     ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched size",
  423.                                          sub.get<DtIds::size>() == it->size);
  424.                     info.typeData = &*it;
  425.                     ++sub;
  426.                 }
  427.                 break;
  428.             }
  429.         }
  430.     }
  431.     // make sure we didn't create a cycle, which should never happen,
  432.     // an alias cannot refer to itself and a structure cannot contain itself
  433.     for (auto& info : types_)
  434.         cycleCheck(&info);
  435.  
  436.     symbols_.reserve(allSyms.count());
  437.     for (auto& sym : allSyms)
  438.     {
  439.         auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
  440.         ADSDATACURSOR_VERIFY("%1%\nSymboldata corrupted: mismatched size", sym.get<SymIds::size>() == it->size);
  441.         symbols_.emplace_back(sym, &*it);
  442.     }
  443.     std::sort(symbols_.begin(), symbols_.end());
  444.  
  445.     // the offset of static vars in function blocks is not given in the datatype info and must therefore be derived from
  446.     // the main symbol
  447.     for (auto& type : types_)
  448.     {
  449.         if (type.typeSpecs.index() != AdsData::DatatypeInfo::classSpec)
  450.             continue;
  451.         for (auto& sub : std::get<AdsData::DatatypeInfo::classSpec>(type.typeSpecs))
  452.         {
  453.             if (!sub.isStatic)
  454.                 continue;
  455.             auto mainSymbol = type.name + '.' + sub.name;
  456.             auto sym        = std::lower_bound(symbols_.begin(), symbols_.end(), mainSymbol);
  457.             ADSDATACURSOR_VERIFY("%1%\nmain symbol for static var %2% not found",
  458.                                  (sym != symbols_.end() && mainSymbol == sym->baseInfo.name), mainSymbol);
  459.             // fix offset
  460.             sub.offset = sym->baseInfo.offset;
  461.         }
  462.     }
  463. }
  464.  
  465. AdsVarData AdsData::operator[](std::string_view name) const
  466. {
  467.     auto curName = name;
  468.     if (auto pos = curName.find('['); pos != curName.npos)
  469.         curName.remove_suffix(curName.size() - pos);
  470.     auto sym = std::upper_bound(symbols_.begin(), symbols_.end(), curName);
  471.     if (sym == symbols_.begin() || (--sym, curName.compare(0, sym->baseInfo.name.size(), sym->baseInfo.name) != 0))
  472.         throw std::out_of_range("var not found: "sv + name);
  473.     auto group  = sym->group;
  474.     auto offset = sym->baseInfo.offset;
  475.     if (name.size() == sym->baseInfo.name.size())
  476.         return AdsVarData{&sym->baseInfo, group, offset};
  477.     curName = std::string_view{name.data() + sym->baseInfo.name.size(), name.size() - sym->baseInfo.name.size()};
  478.     if (curName[0] != '.' && curName[0] != '[')
  479.         throw std::out_of_range("var not found: "sv + name);
  480.     auto dt = followAlias(sym->baseInfo.typeData);
  481.     for (;;)
  482.     {
  483.         if (curName[0] == '.')
  484.         {
  485.             if (dt->typeSpecs.index() != AdsData::DatatypeInfo::classSpec)
  486.                 throw std::out_of_range(
  487.                     "has no subobjects: "s
  488.                     + std::string_view{name.data(), implicit_cast<std::size_t>(curName.data() - name.data())}
  489.                     + " with "sv + curName);
  490.             curName.remove_prefix(1); // '.'
  491.             auto shortName = curName;
  492.             auto pos       = shortName.find_first_of(".["sv);
  493.             if (pos != shortName.npos)
  494.             {
  495.                 shortName.remove_suffix(shortName.size() - pos);
  496.             }
  497.             auto& subs = std::get<AdsData::DatatypeInfo::classSpec>(dt->typeSpecs);
  498.             auto  sub  = std::find_if(subs.begin(), subs.end(), [=](auto& v) { return icmp_equal(shortName, v.name); });
  499.             if (sub == subs.end())
  500.                 throw std::out_of_range(
  501.                     "subobjects not found: "s + shortName + " of "sv
  502.                     + std::string_view{name.data(), implicit_cast<std::size_t>(curName.data() - name.data())}
  503.                     + " with "sv + name);
  504.             if (sub->isStatic)
  505.                 offset = sub->offset;
  506.             else
  507.                 offset += sub->offset;
  508.             if (pos == shortName.npos)
  509.                 return AdsVarData{&*sub, group, offset};
  510.             curName.remove_prefix(pos);
  511.             dt = followAlias(sub->typeData);
  512.         }
  513.         else
  514.         {
  515.             // cur_name[0] == '['
  516.             if (dt->typeSpecs.index() != AdsData::DatatypeInfo::arraySpec)
  517.                 throw std::out_of_range(
  518.                     "is no array: "s
  519.                     + std::string_view{name.data(), implicit_cast<std::size_t>(curName.data() - name.data())}
  520.                     + " with "sv + curName);
  521.             curName.remove_prefix(1); // '['
  522.             auto pos = curName.find(']');
  523.             if (pos == curName.npos)
  524.                 throw std::out_of_range("missing ]");
  525.             auto index = curName;
  526.             index.remove_suffix(index.size() - pos);
  527.             auto& info = std::get<AdsData::DatatypeInfo::arraySpec>(dt->typeSpecs);
  528.             auto  i    = info.index(index);
  529.             offset += info.elemSize() * i;
  530.             curName.remove_prefix(pos + 1); // "index]"
  531.             if (curName.empty())
  532.                 return AdsVarData{&info, group, offset, i};
  533.             if (curName[0] != '[' && curName[0] != '.')
  534.                 throw std::out_of_range("missing . or [");
  535.             dt = followAlias(info.typeData);
  536.         }
  537.     }
  538. }
  539.  
  540. AdsData::iterator AdsData::begin() const noexcept { return iterator{symbols_.begin()}; }
  541. AdsData::iterator AdsData::end() const noexcept { return iterator{symbols_.end()}; }
  542. AdsData::iterator AdsData::cbegin() const noexcept { return begin(); }
  543. AdsData::iterator AdsData::cend() const noexcept { return end(); }
  544. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  545. std::string AdsVarData::name(std::string prefix) const
  546. {
  547.     if (!info_->name.empty())
  548.     {
  549.         prefix.reserve(prefix.size() + 1 + info_->name.size());
  550.         if (!prefix.empty())
  551.             prefix += '.';
  552.         prefix += info_->name;
  553.         return prefix;
  554.     }
  555.     else
  556.         return std::move(prefix) + shortName();
  557. }
  558. std::string AdsVarData::shortName() const
  559. {
  560.     return info_->name.empty() ? static_cast<const AdsData::ArrayInfo*>(info_)->toString(index_) : info_->name;
  561. }
  562. const std::string& AdsVarData::type() const noexcept { return info_->typeData->name; }
  563. const std::string& AdsVarData::comment() const noexcept { return info_->comment; }
  564. DatatypeId         AdsVarData::typeId() const noexcept { return info_->typeData->id; }
  565. SizeType           AdsVarData::group() const noexcept { return group_; }
  566. SizeType           AdsVarData::offset() const noexcept { return offset_; }
  567. SizeType           AdsVarData::size() const noexcept { return info_->typeData->size; }
  568.  
  569. bool AdsVarData::isPointer() const noexcept { return followAlias(info_->typeData)->isPointer; }
  570. bool AdsVarData::isReference() const noexcept { return followAlias(info_->typeData)->isReference; }
  571.  
  572. bool AdsVarData::isStatic() const noexcept { return info_->isStatic; }
  573.  
  574. bool AdsVarData::empty() const noexcept { return subElements() == 0; }
  575.  
  576. SizeType AdsVarData::subElements() const noexcept
  577. {
  578.     auto real_type = followAlias(info_->typeData);
  579.     switch (real_type->typeSpecs.index())
  580.     {
  581.         default:
  582.             assert(false);
  583.         case AdsData::DatatypeInfo::baseSpec:
  584.         case AdsData::DatatypeInfo::compoundSpec:
  585.             return 0;
  586.         case AdsData::DatatypeInfo::arraySpec:
  587.             return std::get<AdsData::DatatypeInfo::arraySpec>(real_type->typeSpecs).numElements();
  588.         case AdsData::DatatypeInfo::classSpec:
  589.             return static_cast<SizeType>(std::get<AdsData::DatatypeInfo::classSpec>(real_type->typeSpecs).size());
  590.     }
  591. }
  592.  
  593. AdsVarData::iterator AdsVarData::begin() const noexcept
  594. {
  595.     auto real_type = followAlias(info_->typeData);
  596.     switch (real_type->typeSpecs.index())
  597.     {
  598.         default:
  599.             assert(false);
  600.         case AdsData::DatatypeInfo::baseSpec:
  601.         case AdsData::DatatypeInfo::compoundSpec:
  602.             return iterator{nullptr, 0, 0, 0};
  603.         case AdsData::DatatypeInfo::arraySpec:
  604.         {
  605.             auto& info = std::get<AdsData::DatatypeInfo::arraySpec>(real_type->typeSpecs);
  606.             return iterator{&info, group_, offset_, 0};
  607.         }
  608.         case AdsData::DatatypeInfo::classSpec:
  609.         {
  610.             auto& info = std::get<AdsData::DatatypeInfo::classSpec>(real_type->typeSpecs);
  611.             return iterator{info.empty() ? nullptr : &info.front(), group_, offset_, 0};
  612.         }
  613.     }
  614. }
  615.  
  616. AdsVarData::iterator AdsVarData::end() const noexcept
  617. {
  618.     auto real_type = followAlias(info_->typeData);
  619.     switch (real_type->typeSpecs.index())
  620.     {
  621.         default:
  622.             assert(false);
  623.         case AdsData::DatatypeInfo::baseSpec:
  624.         case AdsData::DatatypeInfo::compoundSpec:
  625.             return iterator{nullptr, 0, 0, 0};
  626.         case AdsData::DatatypeInfo::arraySpec:
  627.         {
  628.             auto& info = std::get<AdsData::DatatypeInfo::arraySpec>(real_type->typeSpecs);
  629.             return iterator{&info, group_, offset_, info.numElements()};
  630.         }
  631.         case AdsData::DatatypeInfo::classSpec:
  632.         {
  633.             auto& info = std::get<AdsData::DatatypeInfo::classSpec>(real_type->typeSpecs);
  634.             return iterator{info.empty() ? nullptr : &info.back() + 1, group_, offset_, 0};
  635.         }
  636.     }
  637. }
  638.  
  639. AdsVarData::iterator AdsVarData::cbegin() const noexcept { return begin(); }
  640. AdsVarData::iterator AdsVarData::cend() const noexcept { return end(); }
  641.  
  642. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  643. AdsData::iterator::reference AdsData::iterator::operator*() const noexcept
  644. {
  645.     return AdsVarData{&iter_->baseInfo, iter_->group, iter_->baseInfo.offset};
  646. }
  647.  
  648. AdsData::iterator::pointer AdsData::iterator::operator->() const noexcept { return **this; }
  649.  
  650. bool operator==(AdsData::iterator lhs, AdsData::iterator rhs) noexcept { return lhs.iter_ == rhs.iter_; }
  651. bool operator!=(AdsData::iterator lhs, AdsData::iterator rhs) noexcept { return lhs.iter_ != rhs.iter_; }
  652.  
  653. AdsData::iterator& AdsData::iterator::operator++() noexcept
  654. {
  655.     ++iter_;
  656.     return *this;
  657. }
  658.  
  659. AdsData::iterator AdsData::iterator::operator++(int) noexcept
  660. {
  661.     auto tmp = *this;
  662.     ++*this;
  663.     return tmp;
  664. }
  665. AdsData::iterator::iterator(std::vector<AdsData::SymbolInfo>::const_iterator it) noexcept : iter_{it} {}
  666.  
  667. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  668.  
  669. AdsVarData::iterator::reference AdsVarData::iterator::operator*() const noexcept
  670. {
  671.     if (info_->name.empty()) // array-element ?
  672.         return AdsVarData{info_, group_, offset_ + index_ * info_->typeData->size, index_};
  673.     else if (info_->isBit)
  674.         return AdsVarData{info_, group_ + 1, info_->isStatic ? info_->offset : offset_ * 8 + info_->offset};
  675.     else
  676.         return AdsVarData{info_, group_, info_->isStatic ? info_->offset : offset_ + info_->offset};
  677. }
  678.  
  679. AdsVarData::iterator::pointer AdsVarData::iterator::operator->() const noexcept { return **this; }
  680.  
  681. bool operator==(const AdsVarData::iterator& lhs, const AdsVarData::iterator& rhs) noexcept
  682. {
  683.     return lhs.info_ == rhs.info_ && lhs.index_ == rhs.index_ && lhs.offset_ == rhs.offset_ && lhs.group_ == rhs.group_;
  684. }
  685.  
  686. bool operator!=(const AdsVarData::iterator& lhs, const AdsVarData::iterator& rhs) noexcept { return !(lhs == rhs); }
  687.  
  688. AdsVarData::iterator& AdsVarData::iterator::operator++() noexcept
  689. {
  690.     if (info_->name.empty()) // array-element ?
  691.         ++index_;
  692.     else
  693.         ++info_;
  694.     return *this;
  695. }
  696.  
  697. AdsVarData::iterator AdsVarData::iterator::operator++(int) noexcept
  698. {
  699.     auto tmp = *this;
  700.     ++*this;
  701.     return tmp;
  702. }
  703.  
  704. AdsVarData::iterator::iterator(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset,
  705.                                SizeType index) noexcept
  706.     : info_{info}, group_{group}, offset_{offset}, index_{index}
  707. {}
Add Comment
Please, Sign In to add comment