Advertisement
Guest User

Untitled

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