comptrie_trie.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #pragma once
  2. #include "comptrie_impl.h"
  3. #include "comptrie_packer.h"
  4. #include "opaque_trie_iterator.h"
  5. #include "leaf_skipper.h"
  6. #include "key_selector.h"
  7. #include <util/generic/buffer.h>
  8. #include <util/generic/ptr.h>
  9. #include <util/generic/vector.h>
  10. #include <util/generic/yexception.h>
  11. #include <util/memory/blob.h>
  12. #include <util/stream/input.h>
  13. #include <utility>
  14. template <class T, class D, class S>
  15. class TCompactTrieBuilder;
  16. namespace NCompactTrie {
  17. template <class TTrie>
  18. class TFirstSymbolIterator;
  19. }
  20. template <class TTrie>
  21. class TSearchIterator;
  22. template <class TTrie>
  23. class TPrefixIterator;
  24. // in case of <char> specialization cannot distinguish between "" and "\0" keys
  25. template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
  26. class TCompactTrie {
  27. public:
  28. typedef T TSymbol;
  29. typedef D TData;
  30. typedef S TPacker;
  31. typedef typename TCompactTrieKeySelector<TSymbol>::TKey TKey;
  32. typedef typename TCompactTrieKeySelector<TSymbol>::TKeyBuf TKeyBuf;
  33. typedef std::pair<TKey, TData> TValueType;
  34. typedef std::pair<size_t, TData> TPhraseMatch;
  35. typedef TVector<TPhraseMatch> TPhraseMatchVector;
  36. typedef TCompactTrieBuilder<T, D, S> TBuilder;
  37. protected:
  38. TBlob DataHolder;
  39. const char* EmptyValue = nullptr;
  40. TPacker Packer;
  41. NCompactTrie::TPackerLeafSkipper<TPacker> Skipper = &Packer; // This should be true for every constructor.
  42. public:
  43. TCompactTrie() = default;
  44. TCompactTrie(const char* d, size_t len, TPacker packer);
  45. TCompactTrie(const char* d, size_t len)
  46. : TCompactTrie{d, len, TPacker{}} {
  47. }
  48. TCompactTrie(const TBlob& data, TPacker packer);
  49. explicit TCompactTrie(const TBlob& data)
  50. : TCompactTrie{data, TPacker{}} {
  51. }
  52. // Skipper should be initialized with &Packer, not with &other.Packer, so you have to redefine these.
  53. TCompactTrie(const TCompactTrie& other);
  54. TCompactTrie(TCompactTrie&& other) noexcept;
  55. TCompactTrie& operator=(const TCompactTrie& other);
  56. TCompactTrie& operator=(TCompactTrie&& other) noexcept;
  57. explicit operator bool() const {
  58. return !IsEmpty();
  59. }
  60. void Init(const char* d, size_t len, TPacker packer = TPacker());
  61. void Init(const TBlob& data, TPacker packer = TPacker());
  62. bool IsInitialized() const;
  63. bool IsEmpty() const;
  64. bool Find(const TSymbol* key, size_t keylen, TData* value = nullptr) const;
  65. bool Find(const TKeyBuf& key, TData* value = nullptr) const {
  66. return Find(key.data(), key.size(), value);
  67. }
  68. TData Get(const TSymbol* key, size_t keylen) const {
  69. TData value;
  70. if (!Find(key, keylen, &value))
  71. ythrow yexception() << "key " << TKey(key, keylen).Quote() << " not found in trie";
  72. return value;
  73. }
  74. TData Get(const TKeyBuf& key) const {
  75. return Get(key.data(), key.size());
  76. }
  77. TData GetDefault(const TKeyBuf& key, const TData& def) const {
  78. TData value;
  79. if (!Find(key.data(), key.size(), &value))
  80. return def;
  81. else
  82. return value;
  83. }
  84. const TBlob& Data() const {
  85. return DataHolder;
  86. };
  87. const NCompactTrie::ILeafSkipper& GetSkipper() const {
  88. return Skipper;
  89. }
  90. TPacker GetPacker() const {
  91. return Packer;
  92. }
  93. bool HasCorrectSkipper() const {
  94. return Skipper.GetPacker() == &Packer;
  95. }
  96. void FindPhrases(const TSymbol* key, size_t keylen, TPhraseMatchVector& matches, TSymbol separator = TSymbol(' ')) const;
  97. void FindPhrases(const TKeyBuf& key, TPhraseMatchVector& matches, TSymbol separator = TSymbol(' ')) const {
  98. return FindPhrases(key.data(), key.size(), matches, separator);
  99. }
  100. bool FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixLen, TData* value = nullptr, bool* hasNext = nullptr) const;
  101. bool FindLongestPrefix(const TKeyBuf& key, size_t* prefixLen, TData* value = nullptr, bool* hasNext = nullptr) const {
  102. return FindLongestPrefix(key.data(), key.size(), prefixLen, value, hasNext);
  103. }
  104. // Return trie, containing all tails for the given key
  105. inline TCompactTrie<T, D, S> FindTails(const TSymbol* key, size_t keylen) const;
  106. TCompactTrie<T, D, S> FindTails(const TKeyBuf& key) const {
  107. return FindTails(key.data(), key.size());
  108. }
  109. bool FindTails(const TSymbol* key, size_t keylen, TCompactTrie<T, D, S>& res) const;
  110. bool FindTails(const TKeyBuf& key, TCompactTrie<T, D, S>& res) const {
  111. return FindTails(key.data(), key.size(), res);
  112. }
  113. // same as FindTails(&key, 1), a bit faster
  114. // return false, if no arc with @label exists
  115. inline bool FindTails(TSymbol label, TCompactTrie<T, D, S>& res) const;
  116. class TConstIterator {
  117. private:
  118. typedef NCompactTrie::TOpaqueTrieIterator TOpaqueTrieIterator;
  119. typedef NCompactTrie::TOpaqueTrie TOpaqueTrie;
  120. friend class TCompactTrie;
  121. TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend, TPacker packer); // only usable from Begin() and End() methods
  122. TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, const TKeyBuf& key, TPacker packer); // only usable from UpperBound() method
  123. public:
  124. TConstIterator() = default;
  125. bool IsEmpty() const {
  126. return !Impl;
  127. } // Almost no other method can be called.
  128. bool operator==(const TConstIterator& other) const;
  129. bool operator!=(const TConstIterator& other) const;
  130. TConstIterator& operator++();
  131. TConstIterator operator++(int /*unused*/);
  132. TConstIterator& operator--();
  133. TConstIterator operator--(int /*unused*/);
  134. TValueType operator*();
  135. TKey GetKey() const;
  136. size_t GetKeySize() const;
  137. TData GetValue() const;
  138. void GetValue(TData& data) const;
  139. const char* GetValuePtr() const;
  140. private:
  141. TPacker Packer;
  142. TCopyPtr<TOpaqueTrieIterator> Impl;
  143. };
  144. TConstIterator Begin() const;
  145. TConstIterator begin() const;
  146. TConstIterator End() const;
  147. TConstIterator end() const;
  148. // Returns an iterator pointing to the smallest key in the trie >= the argument.
  149. // TODO: misleading name. Should be called LowerBound for consistency with stl.
  150. // No. It is the STL that has a misleading name.
  151. // LowerBound of X cannot be greater than X.
  152. TConstIterator UpperBound(const TKeyBuf& key) const;
  153. void Print(IOutputStream& os);
  154. size_t Size() const;
  155. friend class NCompactTrie::TFirstSymbolIterator<TCompactTrie>;
  156. friend class TSearchIterator<TCompactTrie>;
  157. friend class TPrefixIterator<TCompactTrie>;
  158. protected:
  159. explicit TCompactTrie(const char* emptyValue);
  160. TCompactTrie(const TBlob& data, const char* emptyValue, TPacker packer = TPacker());
  161. bool LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos, bool& hasNext) const;
  162. bool LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos) const {
  163. bool hasNext;
  164. return LookupLongestPrefix(key, keylen, prefixLen, valuepos, hasNext);
  165. }
  166. void LookupPhrases(const char* datapos, size_t len, const TSymbol* key, size_t keylen, TVector<TPhraseMatch>& matches, TSymbol separator) const;
  167. };
  168. template <class T = char, class D = ui64, class S = TCompactTriePacker<D>>
  169. class TCompactTrieHolder: public TCompactTrie<T, D, S>, NNonCopyable::TNonCopyable {
  170. private:
  171. typedef TCompactTrie<T, D, S> TBase;
  172. TArrayHolder<char> Storage;
  173. public:
  174. TCompactTrieHolder(IInputStream& is, size_t len);
  175. };
  176. //------------------------//
  177. // Implementation section //
  178. //------------------------//
  179. // TCompactTrie
  180. template <class T, class D, class S>
  181. TCompactTrie<T, D, S>::TCompactTrie(const TBlob& data, TPacker packer)
  182. : DataHolder(data)
  183. , Packer(packer)
  184. {
  185. Init(data, packer);
  186. }
  187. template <class T, class D, class S>
  188. TCompactTrie<T, D, S>::TCompactTrie(const char* d, size_t len, TPacker packer)
  189. : Packer(packer)
  190. {
  191. Init(d, len, packer);
  192. }
  193. template <class T, class D, class S>
  194. TCompactTrie<T, D, S>::TCompactTrie(const char* emptyValue)
  195. : EmptyValue(emptyValue)
  196. {
  197. }
  198. template <class T, class D, class S>
  199. TCompactTrie<T, D, S>::TCompactTrie(const TBlob& data, const char* emptyValue, TPacker packer)
  200. : DataHolder(data)
  201. , EmptyValue(emptyValue)
  202. , Packer(packer)
  203. {
  204. }
  205. template <class T, class D, class S>
  206. TCompactTrie<T, D, S>::TCompactTrie(const TCompactTrie& other)
  207. : DataHolder(other.DataHolder)
  208. , EmptyValue(other.EmptyValue)
  209. , Packer(other.Packer)
  210. {
  211. }
  212. template <class T, class D, class S>
  213. TCompactTrie<T, D, S>::TCompactTrie(TCompactTrie&& other) noexcept
  214. : DataHolder(std::move(other.DataHolder))
  215. , EmptyValue(std::move(other.EmptyValue))
  216. , Packer(std::move(other.Packer))
  217. {
  218. }
  219. template <class T, class D, class S>
  220. TCompactTrie<T, D, S>& TCompactTrie<T, D, S>::operator=(const TCompactTrie& other) {
  221. if (this != &other) {
  222. DataHolder = other.DataHolder;
  223. EmptyValue = other.EmptyValue;
  224. Packer = other.Packer;
  225. }
  226. return *this;
  227. }
  228. template <class T, class D, class S>
  229. TCompactTrie<T, D, S>& TCompactTrie<T, D, S>::operator=(TCompactTrie&& other) noexcept {
  230. if (this != &other) {
  231. DataHolder = std::move(other.DataHolder);
  232. EmptyValue = std::move(other.EmptyValue);
  233. Packer = std::move(other.Packer);
  234. }
  235. return *this;
  236. }
  237. template <class T, class D, class S>
  238. void TCompactTrie<T, D, S>::Init(const char* d, size_t len, TPacker packer) {
  239. Init(TBlob::NoCopy(d, len), packer);
  240. }
  241. template <class T, class D, class S>
  242. void TCompactTrie<T, D, S>::Init(const TBlob& data, TPacker packer) {
  243. using namespace NCompactTrie;
  244. DataHolder = data;
  245. Packer = packer;
  246. const char* datapos = DataHolder.AsCharPtr();
  247. size_t len = DataHolder.Length();
  248. if (!len)
  249. return;
  250. const char* const dataend = datapos + len;
  251. const char* emptypos = datapos;
  252. char flags = LeapByte(emptypos, dataend, 0);
  253. if (emptypos && (flags & MT_FINAL)) {
  254. Y_ASSERT(emptypos <= dataend);
  255. EmptyValue = emptypos;
  256. }
  257. }
  258. template <class T, class D, class S>
  259. bool TCompactTrie<T, D, S>::IsInitialized() const {
  260. return DataHolder.Data() != nullptr;
  261. }
  262. template <class T, class D, class S>
  263. bool TCompactTrie<T, D, S>::IsEmpty() const {
  264. return DataHolder.Size() == 0 && EmptyValue == nullptr;
  265. }
  266. template <class T, class D, class S>
  267. bool TCompactTrie<T, D, S>::Find(const TSymbol* key, size_t keylen, TData* value) const {
  268. size_t prefixLen = 0;
  269. const char* valuepos = nullptr;
  270. bool hasNext;
  271. if (!LookupLongestPrefix(key, keylen, prefixLen, valuepos, hasNext) || prefixLen != keylen)
  272. return false;
  273. if (value)
  274. Packer.UnpackLeaf(valuepos, *value);
  275. return true;
  276. }
  277. template <class T, class D, class S>
  278. void TCompactTrie<T, D, S>::FindPhrases(const TSymbol* key, size_t keylen, TPhraseMatchVector& matches, TSymbol separator) const {
  279. LookupPhrases(DataHolder.AsCharPtr(), DataHolder.Length(), key, keylen, matches, separator);
  280. }
  281. template <class T, class D, class S>
  282. inline TCompactTrie<T, D, S> TCompactTrie<T, D, S>::FindTails(const TSymbol* key, size_t keylen) const {
  283. TCompactTrie<T, D, S> ret;
  284. FindTails(key, keylen, ret);
  285. return ret;
  286. }
  287. template <class T, class D, class S>
  288. bool TCompactTrie<T, D, S>::FindTails(const TSymbol* key, size_t keylen, TCompactTrie<T, D, S>& res) const {
  289. using namespace NCompactTrie;
  290. size_t len = DataHolder.Length();
  291. if (!key || !len)
  292. return false;
  293. if (!keylen) {
  294. res = *this;
  295. return true;
  296. }
  297. const char* datastart = DataHolder.AsCharPtr();
  298. const char* datapos = datastart;
  299. const char* const dataend = datapos + len;
  300. const TSymbol* keyend = key + keylen;
  301. const char* value = nullptr;
  302. while (key != keyend) {
  303. T label = *(key++);
  304. if (!NCompactTrie::Advance(datapos, dataend, value, label, Packer))
  305. return false;
  306. if (key == keyend) {
  307. if (datapos) {
  308. Y_ASSERT(datapos >= datastart);
  309. res = TCompactTrie<T, D, S>(TBlob::NoCopy(datapos, dataend - datapos), value);
  310. } else {
  311. res = TCompactTrie<T, D, S>(value);
  312. }
  313. return true;
  314. } else if (!datapos) {
  315. return false; // No further way
  316. }
  317. }
  318. return false;
  319. }
  320. template <class T, class D, class S>
  321. inline bool TCompactTrie<T, D, S>::FindTails(TSymbol label, TCompactTrie<T, D, S>& res) const {
  322. using namespace NCompactTrie;
  323. const size_t len = DataHolder.Length();
  324. if (!len)
  325. return false;
  326. const char* datastart = DataHolder.AsCharPtr();
  327. const char* dataend = datastart + len;
  328. const char* datapos = datastart;
  329. const char* value = nullptr;
  330. if (!NCompactTrie::Advance(datapos, dataend, value, label, Packer))
  331. return false;
  332. if (datapos) {
  333. Y_ASSERT(datapos >= datastart);
  334. res = TCompactTrie<T, D, S>(TBlob::NoCopy(datapos, dataend - datapos), value);
  335. } else {
  336. res = TCompactTrie<T, D, S>(value);
  337. }
  338. return true;
  339. }
  340. template <class T, class D, class S>
  341. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::Begin() const {
  342. NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
  343. return TConstIterator(self, EmptyValue, false, Packer);
  344. }
  345. template <class T, class D, class S>
  346. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::begin() const {
  347. return Begin();
  348. }
  349. template <class T, class D, class S>
  350. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::End() const {
  351. NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
  352. return TConstIterator(self, EmptyValue, true, Packer);
  353. }
  354. template <class T, class D, class S>
  355. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::end() const {
  356. return End();
  357. }
  358. template <class T, class D, class S>
  359. size_t TCompactTrie<T, D, S>::Size() const {
  360. size_t res = 0;
  361. for (TConstIterator it = Begin(); it != End(); ++it)
  362. ++res;
  363. return res;
  364. }
  365. template <class T, class D, class S>
  366. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::UpperBound(const TKeyBuf& key) const {
  367. NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
  368. return TConstIterator(self, EmptyValue, key, Packer);
  369. }
  370. template <class T, class D, class S>
  371. void TCompactTrie<T, D, S>::Print(IOutputStream& os) {
  372. typedef typename ::TCompactTrieKeySelector<T>::TKeyBuf TSBuffer;
  373. for (TConstIterator it = Begin(); it != End(); ++it) {
  374. os << TSBuffer((*it).first.data(), (*it).first.size()) << "\t" << (*it).second << Endl;
  375. }
  376. }
  377. template <class T, class D, class S>
  378. bool TCompactTrie<T, D, S>::FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixLen, TData* value, bool* hasNext) const {
  379. const char* valuepos = nullptr;
  380. size_t tempPrefixLen = 0;
  381. bool tempHasNext;
  382. bool found = LookupLongestPrefix(key, keylen, tempPrefixLen, valuepos, tempHasNext);
  383. if (prefixLen)
  384. *prefixLen = tempPrefixLen;
  385. if (found && value)
  386. Packer.UnpackLeaf(valuepos, *value);
  387. if (hasNext)
  388. *hasNext = tempHasNext;
  389. return found;
  390. }
  391. template <class T, class D, class S>
  392. bool TCompactTrie<T, D, S>::LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos, bool& hasNext) const {
  393. using namespace NCompactTrie;
  394. const char* datapos = DataHolder.AsCharPtr();
  395. size_t len = DataHolder.Length();
  396. prefixLen = 0;
  397. hasNext = false;
  398. bool found = false;
  399. if (EmptyValue) {
  400. valuepos = EmptyValue;
  401. found = true;
  402. }
  403. if (!key || !len)
  404. return found;
  405. const char* const dataend = datapos + len;
  406. const T* keyend = key + keylen;
  407. while (key != keyend) {
  408. T label = *(key++);
  409. for (i64 i = (i64)ExtraBits<TSymbol>(); i >= 0; i -= 8) {
  410. const char flags = LeapByte(datapos, dataend, (char)(label >> i));
  411. if (!datapos) {
  412. return found; // no such arc
  413. }
  414. Y_ASSERT(datapos <= dataend);
  415. if ((flags & MT_FINAL)) {
  416. prefixLen = keylen - (keyend - key) - (i ? 1 : 0);
  417. valuepos = datapos;
  418. hasNext = flags & MT_NEXT;
  419. found = true;
  420. if (!i && key == keyend) { // last byte, and got a match
  421. return found;
  422. }
  423. datapos += Packer.SkipLeaf(datapos); // skip intermediate leaf nodes
  424. }
  425. if (!(flags & MT_NEXT)) {
  426. return found; // no further way
  427. }
  428. }
  429. }
  430. return found;
  431. }
  432. template <class T, class D, class S>
  433. void TCompactTrie<T, D, S>::LookupPhrases(
  434. const char* datapos, size_t len, const TSymbol* key, size_t keylen,
  435. TVector<TPhraseMatch>& matches, TSymbol separator) const {
  436. using namespace NCompactTrie;
  437. matches.clear();
  438. if (!key || !len)
  439. return;
  440. const T* const keystart = key;
  441. const T* const keyend = key + keylen;
  442. const char* const dataend = datapos + len;
  443. while (datapos && key != keyend) {
  444. T label = *(key++);
  445. const char* value = nullptr;
  446. if (!Advance(datapos, dataend, value, label, Packer)) {
  447. return;
  448. }
  449. if (value && (key == keyend || *key == separator)) {
  450. size_t matchlength = (size_t)(key - keystart);
  451. D data;
  452. Packer.UnpackLeaf(value, data);
  453. matches.push_back(TPhraseMatch(matchlength, data));
  454. }
  455. }
  456. }
  457. // TCompactTrieHolder
  458. template <class T, class D, class S>
  459. TCompactTrieHolder<T, D, S>::TCompactTrieHolder(IInputStream& is, size_t len)
  460. : Storage(new char[len])
  461. {
  462. if (is.Load(Storage.Get(), len) != len) {
  463. ythrow yexception() << "bad data load";
  464. }
  465. TBase::Init(Storage.Get(), len);
  466. }
  467. //----------------------------------------------------------------------------------------------------------------
  468. // TCompactTrie::TConstIterator
  469. template <class T, class D, class S>
  470. TCompactTrie<T, D, S>::TConstIterator::TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend, TPacker packer)
  471. : Packer(packer)
  472. , Impl(new TOpaqueTrieIterator(trie, emptyValue, atend))
  473. {
  474. }
  475. template <class T, class D, class S>
  476. TCompactTrie<T, D, S>::TConstIterator::TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, const TKeyBuf& key, TPacker packer)
  477. : Packer(packer)
  478. , Impl(new TOpaqueTrieIterator(trie, emptyValue, true))
  479. {
  480. Impl->UpperBound<TSymbol>(key);
  481. }
  482. template <class T, class D, class S>
  483. bool TCompactTrie<T, D, S>::TConstIterator::operator==(const TConstIterator& other) const {
  484. if (!Impl)
  485. return !other.Impl;
  486. if (!other.Impl)
  487. return false;
  488. return *Impl == *other.Impl;
  489. }
  490. template <class T, class D, class S>
  491. bool TCompactTrie<T, D, S>::TConstIterator::operator!=(const TConstIterator& other) const {
  492. return !operator==(other);
  493. }
  494. template <class T, class D, class S>
  495. typename TCompactTrie<T, D, S>::TConstIterator& TCompactTrie<T, D, S>::TConstIterator::operator++() {
  496. Impl->Forward();
  497. return *this;
  498. }
  499. template <class T, class D, class S>
  500. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::TConstIterator::operator++(int /*unused*/) {
  501. TConstIterator copy(*this);
  502. Impl->Forward();
  503. return copy;
  504. }
  505. template <class T, class D, class S>
  506. typename TCompactTrie<T, D, S>::TConstIterator& TCompactTrie<T, D, S>::TConstIterator::operator--() {
  507. Impl->Backward();
  508. return *this;
  509. }
  510. template <class T, class D, class S>
  511. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::TConstIterator::operator--(int /*unused*/) {
  512. TConstIterator copy(*this);
  513. Impl->Backward();
  514. return copy;
  515. }
  516. template <class T, class D, class S>
  517. typename TCompactTrie<T, D, S>::TValueType TCompactTrie<T, D, S>::TConstIterator::operator*() {
  518. return TValueType(GetKey(), GetValue());
  519. }
  520. template <class T, class D, class S>
  521. typename TCompactTrie<T, D, S>::TKey TCompactTrie<T, D, S>::TConstIterator::GetKey() const {
  522. return Impl->GetKey<TSymbol>();
  523. }
  524. template <class T, class D, class S>
  525. size_t TCompactTrie<T, D, S>::TConstIterator::GetKeySize() const {
  526. return Impl->MeasureKey<TSymbol>();
  527. }
  528. template <class T, class D, class S>
  529. const char* TCompactTrie<T, D, S>::TConstIterator::GetValuePtr() const {
  530. return Impl->GetValuePtr();
  531. }
  532. template <class T, class D, class S>
  533. typename TCompactTrie<T, D, S>::TData TCompactTrie<T, D, S>::TConstIterator::GetValue() const {
  534. D data;
  535. GetValue(data);
  536. return data;
  537. }
  538. template <class T, class D, class S>
  539. void TCompactTrie<T, D, S>::TConstIterator::GetValue(typename TCompactTrie<T, D, S>::TData& data) const {
  540. const char* ptr = GetValuePtr();
  541. if (ptr) {
  542. Packer.UnpackLeaf(ptr, data);
  543. } else {
  544. data = typename TCompactTrie<T, D, S>::TData();
  545. }
  546. }