Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cassert>
- #include <cctype>
- #include <cstring>
- #include <optional>
- #include <stdexcept>
- #include <string>
- #include <string_view>
- #include <type_traits>
- #include <variant>
- #include <vector>
- #include "adsData.h"
- using namespace std::literals::string_literals;
- using namespace std::literals::string_view_literals;
- AdsVarData::AdsVarData() noexcept : info_() {}
- AdsVarData::AdsVarData(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset, SizeType index = 0u - 1u)
- : info_{info}, group_{group}, offset_{offset}, index_{index}
- {}
- namespace
- {
- std::string operator+(std::string lhs, std::string_view rhs)
- {
- return std::move(lhs.append(rhs.data(), rhs.size()));
- }
- std::string operator+(std::string_view lhs, std::string_view rhs)
- {
- std::string result;
- result.reserve(lhs.size() + rhs.size());
- result.assign(lhs.data(), lhs.size()).append(rhs);
- return result;
- }
- using SizeType = AdsData::SizeType;
- inline bool icmp_less(std::string_view lhs, std::string_view rhs)
- {
- return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), [](auto x, auto y) {
- return x == '\0'
- ? y != '\0'
- : y == '\0' ? false : x == '.' ? y != '.' : y == '.' ? false : std::tolower(x) < std::tolower(y);
- });
- }
- inline bool icmp_equal(std::string_view lhs, std::string_view rhs)
- {
- return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(),
- [](auto x, auto y) { return std::tolower(x) == std::tolower(y); });
- }
- using adsDataCursor::AdsDataCursor;
- using adsDataCursor::AdsTypeTag;
- using adsDataCursor::DatatypeId;
- using adsDataCursor::IdList;
- using adsDataCursor::implicit_cast;
- using adsDataCursor::LimitMode;
- template <LimitMode limitMode = LimitMode::byCount>
- using DtCursor = AdsDataCursor<AdsTypeTag::datatypeEntry, limitMode, limitMode == LimitMode::bySize>;
- template <LimitMode limitMode = LimitMode::byCount>
- using SymCursor = AdsDataCursor<AdsTypeTag::symbolEntry, limitMode, limitMode == LimitMode::bySize>;
- using ArrayInfoCursor = AdsDataCursor<AdsTypeTag::datatypeArrayInfo, LimitMode::byCount, false>;
- using DtIds = IdList<AdsTypeTag::datatypeEntry>;
- using SymIds = IdList<AdsTypeTag::symbolEntry>;
- using ArrIds = IdList<AdsTypeTag::datatypeArrayInfo>;
- } // namespace
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- class AdsData::SubSymbolInfo
- {
- public:
- SubSymbolInfo(std::string_view name, SizeType offset, bool isStatic, bool isBit,
- AdsData::DatatypeInfo* typeData = nullptr)
- : name(name), offset(offset), isStatic(isStatic), isBit(isBit), typeData(typeData)
- {}
- std::string name;
- SizeType offset;
- bool isStatic;
- bool isBit;
- AdsData::DatatypeInfo* typeData;
- friend bool operator==(const SubSymbolInfo& lhs, const SubSymbolInfo& rhs)
- {
- return icmp_equal(lhs.name, rhs.name);
- }
- friend bool operator==(const SubSymbolInfo& lhs, std::string_view rhs) { return icmp_equal(lhs.name, rhs); }
- friend bool operator==(std::string_view lhs, const SubSymbolInfo& rhs) { return icmp_equal(lhs, rhs.name); }
- };
- class AdsData::SymbolInfo
- {
- public:
- SubSymbolInfo baseInfo;
- SizeType group;
- SymbolInfo(const SymCursor<>& sym, DatatypeInfo* typeData)
- : baseInfo(sym.get<SymIds::name>(), sym.get<SymIds::offset>(), sym.get<SymIds::isStatic>(),
- sym.get<SymIds::isBitValue>(), typeData),
- group(sym.get<SymIds::group>())
- {}
- friend bool operator<(const SymbolInfo& lhs, const SymbolInfo& rhs)
- {
- return icmp_less(lhs.baseInfo.name, rhs.baseInfo.name);
- }
- friend bool operator<(const SymbolInfo& lhs, std::string_view rhs) { return icmp_less(lhs.baseInfo.name, rhs); }
- friend bool operator<(std::string_view lhs, const SymbolInfo& rhs) { return icmp_less(lhs, rhs.baseInfo.name); }
- };
- class AdsData::ArrayInfo : public SubSymbolInfo
- {
- struct AdsDatatypeArrayInfo
- {
- constexpr AdsDatatypeArrayInfo(const ArrayInfoCursor& cursor)
- : lBound(cursor.get<ArrIds::lBound>()), elements(cursor.get<ArrIds::elements>())
- {}
- std::uint32_t lBound;
- std::uint32_t elements;
- };
- std::vector<AdsDatatypeArrayInfo> arrayInfoData_;
- SizeType numElements_;
- public:
- explicit ArrayInfo(const DtCursor<>& dt, std::string_view name = ""sv)
- : AdsData::SubSymbolInfo(name, 0, false, false), arrayInfoData_{}, numElements_{1}
- {
- auto arrayInfoData = dt.get<DtIds::arrayInfoData>();
- assert(arrayInfoData.count() != 0);
- arrayInfoData_.reserve(arrayInfoData.count());
- for (; arrayInfoData; ++arrayInfoData)
- {
- auto& info = arrayInfoData_.emplace_back(arrayInfoData);
- SizeType rBound = info.lBound + info.elements - 1;
- ADSDATACURSOR_VERIFY("%1%\narray info corrupted with\ninfo.elements == %2%\ninfo.lBound == %3%\nrBound == "
- "%4%",
- info.elements != 0 && rBound >= info.lBound, info.elements, info.lBound, rBound);
- ADSDATACURSOR_VERIFY("%1%", std::numeric_limits<SizeType>::max() / info.elements >= numElements_);
- numElements_ *= info.elements;
- }
- }
- SizeType index(std::string_view i) const
- {
- auto workIndex = i;
- SizeType realIndex = 0;
- for (auto& info : arrayInfoData_)
- {
- auto pos = workIndex.find(',');
- if ((&info == &arrayInfoData_.back()) != (pos == workIndex.npos))
- throw std::out_of_range("index with wrong number of dimensions: "s + i);
- auto curIndex = workIndex;
- if (pos != workIndex.npos)
- {
- curIndex.remove_suffix(curIndex.size() - pos);
- workIndex.remove_prefix(pos + 1);
- }
- auto n = svtoi(curIndex);
- if (n < info.lBound || n - info.lBound >= info.elements)
- throw std::out_of_range("index out of range: "s + i);
- // we don't need to check for overflow here since the constructor already ensures that
- // indizes stay within proper bounds
- realIndex = realIndex * info.elements + (n - info.lBound);
- }
- return realIndex;
- }
- std::string toString(SizeType i) const
- {
- if (i >= numElements_)
- throw std::out_of_range("index out of range");
- std::string result = "]";
- for (auto it = arrayInfoData_.cend(); it != arrayInfoData_.cbegin();)
- {
- auto& info = *--it;
- auto curIndex = i % info.elements + info.lBound;
- i /= info.elements;
- do
- {
- result.push_back(static_cast<char>('0' + curIndex % 10));
- } while (curIndex /= 10);
- if (&info != &arrayInfoData_.front())
- result.push_back(',');
- }
- result.push_back('[');
- std::reverse(result.begin(), result.end());
- return result;
- }
- SizeType elemSize() const noexcept;
- SizeType numElements() const noexcept { return numElements_; }
- static SizeType svtoi(std::string_view s)
- {
- SizeType result = 0;
- if (s.empty())
- throw std::out_of_range("index corrupted");
- for (; !s.empty(); s.remove_prefix(1))
- {
- if (s[0] < '0' || s[0] > '9')
- throw std::out_of_range("index corrupted");
- auto curDigit = static_cast<unsigned char>(s[0] - '0');
- if ((std::numeric_limits<SizeType>::max() - curDigit) / 10 < result)
- throw std::out_of_range("index corrupted");
- result = result * 10 + curDigit;
- }
- return result;
- }
- };
- class AdsData::DatatypeInfo
- {
- public:
- struct Category
- {
- enum : std::size_t
- {
- base,
- alias,
- pointer,
- reference,
- array,
- class_ // class_ = struct, union, function block
- };
- };
- using SpecType = std::variant<std::monostate,
- DatatypeInfo*, // alias
- SubSymbolInfo, // pointer
- SubSymbolInfo, // reference
- ArrayInfo, // array
- std::vector<SubSymbolInfo>>;
- DatatypeInfo(std::string_view name, SizeType size, DatatypeId id)
- : name(name), size(size), id(id), typeSpecs(std::in_place_index_t<Category::base>{})
- {}
- explicit DatatypeInfo(const DtCursor<>& dt)
- : name(dt.get<DtIds::name>()), size(dt.get<DtIds::size>()), id(dt.get<DtIds::typeId>())
- {
- ADSDATACURSOR_VERIFY("%1%\nEntry must be either datatype or dataitem",
- dt.get<DtIds::isDatatype>() != dt.get<DtIds::isDataitem>());
- ADSDATACURSOR_VERIFY("%1%\ndatatype cannot be both array and struct/union at the same time",
- !dt.get<DtIds::isDatatype>()
- || (dt.get<DtIds::numArrayDims>() == 0 || dt.get<DtIds::numSubItems>() == 0));
- ADSDATACURSOR_VERIFY("%1%\ndataitem cannot contain subelements",
- !dt.get<DtIds::isDataitem>()
- || (dt.get<DtIds::numArrayDims>() == 0 && dt.get<DtIds::numSubItems>() == 0));
- static constexpr auto ptrStr = "POINTER TO "sv;
- static constexpr auto refStr = "REFERENCE TO "sv;
- if (name.compare(0, ptrStr.size(), ptrStr) == 0)
- {
- typeSpecs.emplace<Category::pointer>(name.substr(ptrStr.size()), 0, false, false);
- size = 4;
- }
- else if (name.compare(0, refStr.size(), refStr) == 0)
- {
- typeSpecs.emplace<Category::reference>(name.substr(refStr.size()), 0, false, false);
- size = 4;
- }
- else if (dt.get<DtIds::numSubItems>() != 0) // struct/union/FB
- {
- auto& subs = typeSpecs.emplace<Category::class_>();
- subs.reserve(dt.get<DtIds::numSubItems>());
- for (auto sub = dt.get<DtIds::subItemData>(); sub; ++sub)
- {
- ADSDATACURSOR_VERIFY("%1%\nsubElements must be dataitems", sub.get<DtIds::isDataitem>());
- subs.emplace_back(sub.get<DtIds::name>(), sub.get<DtIds::offset>(), sub.get<DtIds::isStatic>(),
- sub.get<DtIds::isBitValue>(), nullptr);
- }
- }
- else if (dt.get<DtIds::numArrayDims>() != 0)
- {
- typeSpecs.emplace<Category::array>(dt);
- size = 0;
- id = DatatypeId::blob_;
- }
- else if (!dt.get<DtIds::type>().empty())
- typeSpecs.emplace<Category::alias>();
- else
- typeSpecs.emplace<Category::base>();
- }
- DatatypeInfo(const DtCursor<>& dt, std::string_view name) : name(name), size(0), id(DatatypeId::blob_)
- {
- ADSDATACURSOR_VERIFY("%1%", dt.get<DtIds::numArrayDims>() != 0);
- typeSpecs.emplace<Category::array>(dt, dt.get<DtIds::type>());
- size = 0;
- id = DatatypeId::blob_;
- }
- std::string name;
- SizeType size;
- DatatypeId id;
- bool visited = false; // used for cycle detection
- SpecType typeSpecs;
- friend bool operator<(const AdsData::DatatypeInfo& lhs, const AdsData::DatatypeInfo& rhs)
- {
- return lhs.name < rhs.name;
- }
- friend bool operator<(const AdsData::DatatypeInfo& lhs, std::string_view rhs) { return lhs.name < rhs; }
- friend bool operator<(std::string_view lhs, const AdsData::DatatypeInfo& rhs) { return lhs == rhs.name; }
- friend bool operator==(const AdsData::DatatypeInfo& lhs, const AdsData::DatatypeInfo& rhs)
- {
- return lhs.name == rhs.name;
- }
- friend bool operator==(const AdsData::DatatypeInfo& lhs, std::string_view rhs) { return lhs.name < rhs; }
- friend bool operator==(std::string_view lhs, const AdsData::DatatypeInfo& rhs) { return lhs == rhs.name; }
- };
- SizeType AdsData::ArrayInfo::elemSize() const noexcept { return typeData->size; }
- namespace
- {
- // check for cycles and fix array size while we're at it
- SizeType cycleCheck(AdsData::DatatypeInfo* p)
- {
- using Category = AdsData::DatatypeInfo::Category;
- ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: cycle detected", !p->visited);
- p->visited = true;
- static constexpr auto deleter = [](auto* x) { x->visited = false; };
- std::unique_ptr<AdsData::DatatypeInfo, decltype(deleter)> guard(p, deleter);
- switch (p->typeSpecs.index())
- {
- default:
- assert(false);
- case Category::base:
- case Category::pointer:
- case Category::reference:
- break;
- case Category::alias:
- cycleCheck(std::get<Category::alias>(p->typeSpecs));
- break;
- case Category::array:
- if (p->size == 0)
- {
- auto& info = std::get<Category::array>(p->typeSpecs);
- auto elemSize = cycleCheck(info.typeData);
- ADSDATACURSOR_VERIFY("%1%", std::numeric_limits<SizeType>::max() / elemSize >= info.numElements())
- p->size = elemSize * info.numElements();
- }
- break;
- case Category::class_:
- for (auto& sub : std::get<Category::class_>(p->typeSpecs))
- cycleCheck(sub.typeData);
- break;
- }
- ADSDATACURSOR_VERIFY("%1%", p->size != 0);
- return p->size;
- }
- const AdsData::DatatypeInfo* followAlias(const AdsData::DatatypeInfo* p) noexcept
- {
- while (auto q = std::get_if<AdsData::DatatypeInfo::Category::alias>(&p->typeSpecs))
- p = *q;
- return p;
- }
- } // namespace
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AdsData::AdsData() noexcept = default;
- AdsData::AdsData(AdsData&&) noexcept = default;
- AdsData& AdsData::operator=(AdsData&&) noexcept = default;
- AdsData::~AdsData() noexcept = default;
- AdsData::AdsData(const std::vector<char>& symData, const std::vector<char>& dtData) : symbols_{}, types_{}
- {
- using Category = DatatypeInfo::Category;
- // count how many datatype entries we have and verify their integrity
- DtCursor<> allDts(&dtData[0], DtCursor<LimitMode::bySize>(&dtData[0], dtData.size()).size());
- // add to types_
- types_.reserve(allDts.count());
- for (auto& dt : allDts)
- types_.emplace_back(dt);
- std::sort(types_.begin(), types_.end());
- // TwinCAT2 doesn't send info about basic datatypes so we add them here as needed
- // we don't link them yet, because adding to the types-vector might cause a reallocation,
- // invalidating references in the process
- // also add missing ARRAY types for POINTER TO ARRAY
- static constexpr auto arrPtrStr = "POINTER TO ARRAY "sv;
- static constexpr auto arrRefStr = "REFERENCE TO ARRAY "sv;
- for (auto& dt : allDts)
- {
- for (auto& sub : dt.get<DtIds::subItemData>())
- {
- ADSDATACURSOR_VERIFY("%1%\nstructure elements must have a type", !sub.get<DtIds::type>().empty());
- auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
- if (it == types_.end() || it->name != sub.get<DtIds::type>())
- types_.emplace(it, sub.get<DtIds::type>(), sub.get<DtIds::size>(), sub.get<DtIds::typeId>());
- }
- if (dt.get<DtIds::type>().empty())
- continue; // base type or structure
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
- if (it == types_.end() || it->name != dt.get<DtIds::type>())
- {
- types_.emplace(it, dt.get<DtIds::type>(), dt.get<DtIds::size>(), dt.get<DtIds::typeId>());
- }
- auto name = dt.get<DtIds::name>();
- if (name.compare(0, arrPtrStr.size(), arrPtrStr) == 0)
- name.remove_prefix("POINTER TO "sv.size());
- else if (name.compare(0, arrRefStr.size(), arrRefStr) == 0)
- name.remove_prefix("REFERENCE TO "sv.size());
- else
- continue;
- auto it2 = std::lower_bound(types_.begin(), types_.end(), name);
- if (it2 == types_.end() || it2->name != name)
- types_.emplace(it2, dt, name);
- }
- // count how many symbol entries we have and verify their integrity
- SymCursor<> allSyms(&symData[0], SymCursor<LimitMode::bySize>(&symData[0], symData.size()).size());
- // add base types as needed (TwinCAT2)
- for (auto& sym : allSyms)
- {
- ADSDATACURSOR_VERIFY("%1%\nsymbols must have a type", !sym.get<SymIds::type>().empty());
- auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
- if (it == types_.end() || it->name != sym.get<SymIds::type>())
- types_.emplace(it, sym.get<SymIds::type>(), sym.get<SymIds::size>(), sym.get<SymIds::typeId>());
- }
- // crosslink datatypes
- for (auto& dt : allDts)
- {
- auto type = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::name>());
- switch (type->typeSpecs.index())
- {
- default:
- assert(false);
- case Category::base:
- break;
- case Category::alias:
- {
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
- std::get<Category::alias>(type->typeSpecs) = &*it;
- ADSDATACURSOR_VERIFY("%1%", dt.get<DtIds::size>() == it->size);
- break;
- }
- case Category::pointer:
- case Category::reference:
- {
- auto& info = type->typeSpecs.index() == Category::pointer
- ? std::get<Category::pointer>(type->typeSpecs)
- : std::get<Category::reference>(type->typeSpecs);
- auto it = std::lower_bound(types_.begin(), types_.end(), info.name);
- ADSDATACURSOR_VERIFY("%1%", it != types_.end() && it->name == info.name);
- info.typeData = &*it;
- info.name = "^"sv;
- break;
- }
- case Category::array:
- {
- auto it = std::lower_bound(types_.begin(), types_.end(), dt.get<DtIds::type>());
- auto& info = std::get<Category::array>(type->typeSpecs);
- ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched element size\ntype->size == %2%\nit->size "
- "== %3%\ninfo.numElements() == %4%",
- type->size == 0 || it->size == 0 || type->size / info.numElements() == it->size,
- type->size, it->size, info.numElements());
- info.typeData = &*it;
- break;
- }
- case Category::class_:
- {
- auto sub = dt.get<DtIds::subItemData>();
- for (auto& info : std::get<Category::class_>(type->typeSpecs))
- {
- auto it = std::lower_bound(types_.begin(), types_.end(), sub.get<DtIds::type>());
- ADSDATACURSOR_VERIFY("%1%\nDatatypes corrupted: mismatched size",
- sub.get<DtIds::size>() == it->size);
- info.typeData = &*it;
- ++sub;
- }
- break;
- }
- }
- }
- // link implicitly added arrays
- for (auto& type : types_)
- {
- if (type.typeSpecs.index() != Category::array)
- continue;
- auto& info = std::get<Category::array>(type.typeSpecs);
- if (info.typeData)
- continue;
- auto it = std::lower_bound(types_.begin(), types_.end(), info.name);
- ADSDATACURSOR_VERIFY("%1%", it != types_.end() && it->name == info.name);
- info.typeData = &*it;
- info.name = ""sv;
- }
- // make sure we didn't create a cycle, which should never happen,
- // an alias cannot refer to itself and a structure cannot contain itself
- // also fix array size
- for (auto& info : types_)
- cycleCheck(&info);
- symbols_.reserve(allSyms.count());
- for (auto& sym : allSyms)
- {
- auto it = std::lower_bound(types_.begin(), types_.end(), sym.get<SymIds::type>());
- ADSDATACURSOR_VERIFY("%1%\nSymboldata corrupted: mismatched size", sym.get<SymIds::size>() == it->size);
- symbols_.emplace_back(sym, &*it);
- }
- std::sort(symbols_.begin(), symbols_.end());
- // the offset of static vars in function blocks is not given in the datatype info and must therefore be derived from
- // the main symbol
- for (auto& type : types_)
- {
- if (type.typeSpecs.index() != Category::class_)
- continue;
- for (auto& sub : std::get<Category::class_>(type.typeSpecs))
- {
- if (!sub.isStatic)
- continue;
- auto mainSymbol = type.name + '.' + sub.name;
- auto sym = std::lower_bound(symbols_.begin(), symbols_.end(), mainSymbol);
- ADSDATACURSOR_VERIFY("%1%\nmain symbol for static var %2% not found",
- (sym != symbols_.end() && mainSymbol == sym->baseInfo.name), mainSymbol);
- // fix offset
- sub.offset = sym->baseInfo.offset;
- }
- }
- }
- AdsVarData AdsData::maybe(std::string_view name) const
- {
- auto curName = name;
- if (auto pos = curName.find('['); pos != curName.npos)
- curName.remove_suffix(curName.size() - pos);
- auto sym = std::upper_bound(symbols_.begin(), symbols_.end(), curName);
- if (sym == symbols_.begin()
- || ((void)--sym, curName.compare(0, sym->baseInfo.name.size(), sym->baseInfo.name) != 0))
- return {};
- AdsVarData data{&sym->baseInfo, sym->group, sym->baseInfo.offset};
- if (name.size() == sym->baseInfo.name.size())
- return data;
- else
- return data.maybe(name.substr(sym->baseInfo.name.size()));
- }
- AdsVarData AdsData::operator[](std::string_view name) const
- {
- if (auto data = maybe(name))
- return data;
- else
- throw std::out_of_range("symbol "sv + name + " not found"sv);
- }
- AdsData::iterator AdsData::begin() const noexcept { return iterator{symbols_.begin()}; }
- AdsData::iterator AdsData::end() const noexcept { return iterator{symbols_.end()}; }
- AdsData::iterator AdsData::cbegin() const noexcept { return begin(); }
- AdsData::iterator AdsData::cend() const noexcept { return end(); }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- std::string AdsVarData::name(std::string prefix) const
- {
- if (!info_->name.empty())
- {
- prefix.reserve(prefix.size() + 1 + info_->name.size());
- if (!prefix.empty() && info_->name != "^"sv)
- prefix += '.';
- prefix += info_->name;
- return prefix;
- }
- else
- return std::move(prefix) + shortName();
- }
- std::string AdsVarData::shortName() const
- {
- return info_->name.empty() ? static_cast<const AdsData::ArrayInfo*>(info_)->toString(index_) : info_->name;
- }
- const std::string& AdsVarData::type() const noexcept { return info_->typeData->name; }
- DatatypeId AdsVarData::typeId() const noexcept { return info_->typeData->id; }
- SizeType AdsVarData::group() const noexcept { return group_; }
- SizeType AdsVarData::offset() const noexcept { return offset_; }
- SizeType AdsVarData::size() const noexcept { return info_->typeData->size; }
- bool AdsVarData::isPointer() const noexcept
- {
- return followAlias(info_->typeData)->typeSpecs.index() == AdsData::DatatypeInfo::Category::pointer;
- }
- bool AdsVarData::isReference() const noexcept
- {
- return followAlias(info_->typeData)->typeSpecs.index() == AdsData::DatatypeInfo::Category::reference;
- }
- bool AdsVarData::isStatic() const noexcept { return info_->isStatic; }
- bool AdsVarData::empty() const noexcept { return subElements() == 0; }
- SizeType AdsVarData::subElements() const noexcept
- {
- using Category = AdsData::DatatypeInfo::Category;
- auto real_type = followAlias(info_->typeData);
- switch (real_type->typeSpecs.index())
- {
- default:
- case Category::alias:
- assert(false);
- case Category::base:
- case Category::pointer:
- case Category::reference:
- return 0;
- case Category::array:
- return std::get<Category::array>(real_type->typeSpecs).numElements();
- case Category::class_:
- return static_cast<SizeType>(std::get<Category::class_>(real_type->typeSpecs).size());
- }
- }
- AdsVarData AdsVarData::deref(SizeType address) const
- {
- ADSDATACURSOR_VERIFY("%1%", isPointer() || isReference());
- using Category = AdsData::DatatypeInfo::Category;
- auto dt = followAlias(info_->typeData);
- auto& info = dt->typeSpecs.index() == Category::pointer ? std::get<Category::pointer>(dt->typeSpecs)
- : std::get<Category::reference>(dt->typeSpecs);
- return {&info, group(), address};
- }
- AdsVarData AdsVarData::maybe(std::string_view name) const
- {
- using Category = AdsData::DatatypeInfo::Category;
- auto dt = followAlias(info_->typeData);
- if (name[0] == '.' && dt->typeSpecs.index() == Category::class_)
- {
- name.remove_prefix(1);
- auto shortName = name;
- auto pos = name.find_first_of(".["sv);
- if (pos != name.npos)
- shortName.remove_suffix(shortName.size() - pos);
- auto& subs = std::get<Category::class_>(dt->typeSpecs);
- auto sub = std::find_if(subs.begin(), subs.end(), [=](auto& v) { return icmp_equal(shortName, v.name); });
- if (sub == subs.end())
- return {};
- AdsVarData subData{&*sub, group(), sub->isStatic ? offset() + sub->offset : sub->offset};
- if (pos == name.npos)
- return subData;
- name.remove_prefix(pos);
- return subData.maybe(name);
- }
- else if (name[0] == '[' && dt->typeSpecs.index() == Category::array)
- {
- name.remove_prefix(1);
- auto pos = name.find(']');
- if (pos == name.npos)
- return {};
- auto index = name;
- index.remove_suffix(index.size() - pos);
- auto& info = std::get<Category::array>(dt->typeSpecs);
- try
- {
- auto i = info.index(index);
- name.remove_prefix(pos + 1); // "index]"
- AdsVarData subData{&info, group(), offset() + info.elemSize() * i, i};
- if (name.empty())
- return subData;
- else
- return subData.maybe(name);
- }
- catch (std::out_of_range&)
- {
- return {};
- }
- }
- else
- return {};
- }
- AdsVarData AdsVarData::operator[](std::string_view name) const
- {
- if (auto data = maybe(name))
- return data;
- else
- throw std::out_of_range("subsymbol "sv + name + " not found in "sv + shortName());
- }
- AdsVarData::iterator AdsVarData::begin() const noexcept
- {
- using Category = AdsData::DatatypeInfo::Category;
- auto real_type = followAlias(info_->typeData);
- switch (real_type->typeSpecs.index())
- {
- default:
- case Category::alias:
- assert(false);
- case Category::base:
- case Category::pointer:
- case Category::reference:
- return iterator{nullptr, 0, 0, 0};
- case Category::array:
- {
- auto& info = std::get<Category::array>(real_type->typeSpecs);
- return iterator{&info, group_, offset_, 0};
- }
- case Category::class_:
- {
- auto& info = std::get<Category::class_>(real_type->typeSpecs);
- return iterator{info.empty() ? nullptr : &info.front(), group_, offset_, 0};
- }
- }
- }
- AdsVarData::iterator AdsVarData::end() const noexcept
- {
- using Category = AdsData::DatatypeInfo::Category;
- auto real_type = followAlias(info_->typeData);
- switch (real_type->typeSpecs.index())
- {
- default:
- case Category::alias:
- assert(false);
- case Category::base:
- case Category::pointer:
- case Category::reference:
- return iterator{nullptr, 0, 0, 0};
- case Category::array:
- {
- auto& info = std::get<Category::array>(real_type->typeSpecs);
- return iterator{&info, group_, offset_, info.numElements()};
- }
- case Category::class_:
- {
- auto& info = std::get<Category::class_>(real_type->typeSpecs);
- return iterator{info.empty() ? nullptr : &info.back() + 1, group_, offset_, 0};
- }
- }
- }
- AdsVarData::iterator AdsVarData::cbegin() const noexcept { return begin(); }
- AdsVarData::iterator AdsVarData::cend() const noexcept { return end(); }
- bool AdsVarData::good() const noexcept { return info_; }
- AdsVarData::operator bool() const noexcept { return good(); }
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AdsData::iterator::reference AdsData::iterator::operator*() const noexcept
- {
- return AdsVarData{&iter_->baseInfo, iter_->group, iter_->baseInfo.offset};
- }
- AdsData::iterator::pointer AdsData::iterator::operator->() const noexcept { return **this; }
- bool operator==(AdsData::iterator lhs, AdsData::iterator rhs) noexcept { return lhs.iter_ == rhs.iter_; }
- bool operator!=(AdsData::iterator lhs, AdsData::iterator rhs) noexcept { return lhs.iter_ != rhs.iter_; }
- AdsData::iterator& AdsData::iterator::operator++() noexcept
- {
- ++iter_;
- return *this;
- }
- AdsData::iterator AdsData::iterator::operator++(int) noexcept
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
- AdsData::iterator::iterator(std::vector<AdsData::SymbolInfo>::const_iterator it) noexcept : iter_{it} {}
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- AdsVarData::iterator::reference AdsVarData::iterator::operator*() const noexcept
- {
- if (info_->name.empty()) // array-element ?
- return AdsVarData{info_, group_, offset_ + index_ * info_->typeData->size, index_};
- else if (info_->isBit)
- return AdsVarData{info_, group_ + 1, info_->isStatic ? info_->offset : offset_ * 8 + info_->offset};
- else
- return AdsVarData{info_, group_, info_->isStatic ? info_->offset : offset_ + info_->offset};
- }
- AdsVarData::iterator::pointer AdsVarData::iterator::operator->() const noexcept { return **this; }
- bool operator==(const AdsVarData::iterator& lhs, const AdsVarData::iterator& rhs) noexcept
- {
- return lhs.info_ == rhs.info_ && lhs.index_ == rhs.index_ && lhs.offset_ == rhs.offset_ && lhs.group_ == rhs.group_;
- }
- bool operator!=(const AdsVarData::iterator& lhs, const AdsVarData::iterator& rhs) noexcept { return !(lhs == rhs); }
- AdsVarData::iterator& AdsVarData::iterator::operator++() noexcept
- {
- if (info_->name.empty()) // array-element ?
- ++index_;
- else
- ++info_;
- return *this;
- }
- AdsVarData::iterator AdsVarData::iterator::operator++(int) noexcept
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
- AdsVarData::iterator::iterator(const AdsData::SubSymbolInfo* info, SizeType group, SizeType offset,
- SizeType index) noexcept
- : info_{info}, group_{group}, offset_{offset}, index_{index}
- {}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement