| 1 | #pragma once |
| 2 | |
| 3 | #include <nn/util.h> |
| 4 | #include <nn/util/AccessorBase.h> |
| 5 | #include <nn/util/util_BinTypes.h> |
| 6 | |
| 7 | namespace nn::util { |
| 8 | |
| 9 | struct ResDicData { |
| 10 | struct Entry { |
| 11 | int32_t refBit; |
| 12 | uint16_t children[2]; |
| 13 | BinPtrToString pKey; |
| 14 | }; |
| 15 | |
| 16 | BinBlockSignature signature; |
| 17 | int32_t count; |
| 18 | Entry entries[1]; |
| 19 | }; |
| 20 | |
| 21 | class ResDic : public AccessorBase<ResDicData> { |
| 22 | NN_NO_COPY(ResDic); |
| 23 | |
| 24 | public: |
| 25 | static const int Npos = -1; |
| 26 | |
| 27 | int GetCount() const { return ToData().count; } |
| 28 | |
| 29 | string_view GetKey(int index) const { return ToData().entries[1 + index].pKey.Get()->Get(); } |
| 30 | |
| 31 | int FindIndex(const string_view& key) const { |
| 32 | const Entry* pEntry = FindImpl(key); |
| 33 | return *pEntry->pKey.Get() == key ? |
| 34 | static_cast<int>(std::distance(first: &ToData().entries[1], last: pEntry)) : |
| 35 | Npos; |
| 36 | } |
| 37 | |
| 38 | bool Build(); |
| 39 | |
| 40 | static size_t CalculateSize(int numEntries) { |
| 41 | size_t size = 0; |
| 42 | size += sizeof(ResDicData); |
| 43 | size += sizeof(ResDicData::Entry) * numEntries; |
| 44 | return size; |
| 45 | } |
| 46 | |
| 47 | private: |
| 48 | static int (const string_view& key, int refBit) { |
| 49 | int charIndex = refBit >> 3; |
| 50 | if (static_cast<size_t>(charIndex) < key.length()) { |
| 51 | int bitIndex = refBit & 7; |
| 52 | return (key[key.length() - charIndex - 1] >> bitIndex) & 1; |
| 53 | } |
| 54 | return 0; |
| 55 | } |
| 56 | |
| 57 | static int FindRefBit(const string_view& lhs, const string_view& rhs); |
| 58 | |
| 59 | static bool Older(const ResDicData::Entry* pParent, const ResDicData::Entry* pChild) { |
| 60 | return pParent->refBit < pChild->refBit; |
| 61 | } |
| 62 | |
| 63 | ResDicData::Entry* GetChild(const ResDicData::Entry* pParent, const string_view& key) { |
| 64 | int childIndex = ExtractRefBit(key, refBit: pParent->refBit); |
| 65 | int entryIndex = pParent->children[childIndex]; |
| 66 | return &ToData().entries[entryIndex]; |
| 67 | } |
| 68 | |
| 69 | const ResDicData::Entry* GetChild(const ResDicData::Entry* parent, |
| 70 | const string_view& key) const { |
| 71 | int bit = ExtractRefBit(key, refBit: parent->refBit); |
| 72 | int index = parent->children[bit]; |
| 73 | return &ToData().entries[index]; |
| 74 | } |
| 75 | |
| 76 | void SetChild(ResDicData::Entry* parent, ResDicData::Entry* child) { |
| 77 | int bit = ExtractRefBit(key: *child->pKey.Get(), refBit: parent->refBit); |
| 78 | auto index = std::distance(first: ToData().entries, last: child); |
| 79 | parent->children[bit] = static_cast<uint16_t>(index); |
| 80 | } |
| 81 | |
| 82 | const ResDicData::Entry* FindImpl(const string_view& key) const { |
| 83 | const Entry* pParent = &ToData().entries[0]; |
| 84 | const Entry* pChild = &ToData().entries[pParent->children[0]]; |
| 85 | |
| 86 | while (Older(pParent, pChild)) { |
| 87 | pParent = pChild; |
| 88 | pChild = GetChild(parent: pChild, key); |
| 89 | } |
| 90 | return pChild; |
| 91 | } |
| 92 | }; |
| 93 | } // namespace nn::util |