1#pragma once
2
3#include <nn/util.h>
4#include <nn/util/AccessorBase.h>
5#include <nn/util/util_BinTypes.h>
6
7namespace nn::util {
8
9struct 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
21class ResDic : public AccessorBase<ResDicData> {
22 NN_NO_COPY(ResDic);
23
24public:
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
47private:
48 static int ExtractRefBit(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