comptrie_trie.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  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(TBlob data, TPacker packer);
  49. explicit TCompactTrie(TBlob data)
  50. : TCompactTrie{std::move(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(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(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(TBlob data, TPacker packer)
  182. {
  183. Init(std::move(data), packer);
  184. }
  185. template <class T, class D, class S>
  186. TCompactTrie<T, D, S>::TCompactTrie(const char* d, size_t len, TPacker packer)
  187. {
  188. Init(d, len, packer);
  189. }
  190. template <class T, class D, class S>
  191. TCompactTrie<T, D, S>::TCompactTrie(const char* emptyValue)
  192. : EmptyValue(emptyValue)
  193. {
  194. }
  195. template <class T, class D, class S>
  196. TCompactTrie<T, D, S>::TCompactTrie(TBlob data, const char* emptyValue, TPacker packer)
  197. : DataHolder(std::move(data))
  198. , EmptyValue(emptyValue)
  199. , Packer(packer)
  200. {
  201. }
  202. template <class T, class D, class S>
  203. TCompactTrie<T, D, S>::TCompactTrie(const TCompactTrie& other)
  204. : DataHolder(other.DataHolder)
  205. , EmptyValue(other.EmptyValue)
  206. , Packer(other.Packer)
  207. {
  208. }
  209. template <class T, class D, class S>
  210. TCompactTrie<T, D, S>::TCompactTrie(TCompactTrie&& other) noexcept
  211. : DataHolder(std::move(other.DataHolder))
  212. , EmptyValue(std::move(other.EmptyValue))
  213. , Packer(std::move(other.Packer))
  214. {
  215. }
  216. template <class T, class D, class S>
  217. TCompactTrie<T, D, S>& TCompactTrie<T, D, S>::operator=(const TCompactTrie& other) {
  218. if (this != &other) {
  219. DataHolder = other.DataHolder;
  220. EmptyValue = other.EmptyValue;
  221. Packer = other.Packer;
  222. }
  223. return *this;
  224. }
  225. template <class T, class D, class S>
  226. TCompactTrie<T, D, S>& TCompactTrie<T, D, S>::operator=(TCompactTrie&& other) noexcept {
  227. if (this != &other) {
  228. DataHolder = std::move(other.DataHolder);
  229. EmptyValue = std::move(other.EmptyValue);
  230. Packer = std::move(other.Packer);
  231. }
  232. return *this;
  233. }
  234. template <class T, class D, class S>
  235. void TCompactTrie<T, D, S>::Init(const char* d, size_t len, TPacker packer) {
  236. Init(TBlob::NoCopy(d, len), packer);
  237. }
  238. template <class T, class D, class S>
  239. void TCompactTrie<T, D, S>::Init(TBlob data, TPacker packer) {
  240. using namespace NCompactTrie;
  241. DataHolder = std::move(data);
  242. Packer = packer;
  243. const char* datapos = DataHolder.AsCharPtr();
  244. size_t len = DataHolder.Length();
  245. if (!len)
  246. return;
  247. const char* const dataend = datapos + len;
  248. const char* emptypos = datapos;
  249. char flags = LeapByte(emptypos, dataend, 0);
  250. if (emptypos && (flags & MT_FINAL)) {
  251. Y_ASSERT(emptypos <= dataend);
  252. EmptyValue = emptypos;
  253. }
  254. }
  255. template <class T, class D, class S>
  256. bool TCompactTrie<T, D, S>::IsInitialized() const {
  257. return DataHolder.Data() != nullptr;
  258. }
  259. template <class T, class D, class S>
  260. bool TCompactTrie<T, D, S>::IsEmpty() const {
  261. return DataHolder.Size() == 0 && EmptyValue == nullptr;
  262. }
  263. template <class T, class D, class S>
  264. bool TCompactTrie<T, D, S>::Find(const TSymbol* key, size_t keylen, TData* value) const {
  265. size_t prefixLen = 0;
  266. const char* valuepos = nullptr;
  267. bool hasNext;
  268. if (!LookupLongestPrefix(key, keylen, prefixLen, valuepos, hasNext) || prefixLen != keylen)
  269. return false;
  270. if (value)
  271. Packer.UnpackLeaf(valuepos, *value);
  272. return true;
  273. }
  274. template <class T, class D, class S>
  275. void TCompactTrie<T, D, S>::FindPhrases(const TSymbol* key, size_t keylen, TPhraseMatchVector& matches, TSymbol separator) const {
  276. LookupPhrases(DataHolder.AsCharPtr(), DataHolder.Length(), key, keylen, matches, separator);
  277. }
  278. template <class T, class D, class S>
  279. inline TCompactTrie<T, D, S> TCompactTrie<T, D, S>::FindTails(const TSymbol* key, size_t keylen) const {
  280. TCompactTrie<T, D, S> ret;
  281. FindTails(key, keylen, ret);
  282. return ret;
  283. }
  284. template <class T, class D, class S>
  285. bool TCompactTrie<T, D, S>::FindTails(const TSymbol* key, size_t keylen, TCompactTrie<T, D, S>& res) const {
  286. using namespace NCompactTrie;
  287. size_t len = DataHolder.Length();
  288. if (!key || !len)
  289. return false;
  290. if (!keylen) {
  291. res = *this;
  292. return true;
  293. }
  294. const char* datastart = DataHolder.AsCharPtr();
  295. const char* datapos = datastart;
  296. const char* const dataend = datapos + len;
  297. const TSymbol* keyend = key + keylen;
  298. const char* value = nullptr;
  299. while (key != keyend) {
  300. T label = *(key++);
  301. if (!NCompactTrie::Advance(datapos, dataend, value, label, Packer))
  302. return false;
  303. if (key == keyend) {
  304. if (datapos) {
  305. Y_ASSERT(datapos >= datastart);
  306. res = TCompactTrie<T, D, S>(TBlob::NoCopy(datapos, dataend - datapos), value);
  307. } else {
  308. res = TCompactTrie<T, D, S>(value);
  309. }
  310. return true;
  311. } else if (!datapos) {
  312. return false; // No further way
  313. }
  314. }
  315. return false;
  316. }
  317. template <class T, class D, class S>
  318. inline bool TCompactTrie<T, D, S>::FindTails(TSymbol label, TCompactTrie<T, D, S>& res) const {
  319. using namespace NCompactTrie;
  320. const size_t len = DataHolder.Length();
  321. if (!len)
  322. return false;
  323. const char* datastart = DataHolder.AsCharPtr();
  324. const char* dataend = datastart + len;
  325. const char* datapos = datastart;
  326. const char* value = nullptr;
  327. if (!NCompactTrie::Advance(datapos, dataend, value, label, Packer))
  328. return false;
  329. if (datapos) {
  330. Y_ASSERT(datapos >= datastart);
  331. res = TCompactTrie<T, D, S>(TBlob::NoCopy(datapos, dataend - datapos), value);
  332. } else {
  333. res = TCompactTrie<T, D, S>(value);
  334. }
  335. return true;
  336. }
  337. template <class T, class D, class S>
  338. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::Begin() const {
  339. NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
  340. return TConstIterator(self, EmptyValue, false, Packer);
  341. }
  342. template <class T, class D, class S>
  343. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::begin() const {
  344. return Begin();
  345. }
  346. template <class T, class D, class S>
  347. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::End() const {
  348. NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
  349. return TConstIterator(self, EmptyValue, true, Packer);
  350. }
  351. template <class T, class D, class S>
  352. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::end() const {
  353. return End();
  354. }
  355. template <class T, class D, class S>
  356. size_t TCompactTrie<T, D, S>::Size() const {
  357. size_t res = 0;
  358. for (TConstIterator it = Begin(); it != End(); ++it)
  359. ++res;
  360. return res;
  361. }
  362. template <class T, class D, class S>
  363. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::UpperBound(const TKeyBuf& key) const {
  364. NCompactTrie::TOpaqueTrie self(DataHolder.AsCharPtr(), DataHolder.Length(), Skipper);
  365. return TConstIterator(self, EmptyValue, key, Packer);
  366. }
  367. template <class T, class D, class S>
  368. void TCompactTrie<T, D, S>::Print(IOutputStream& os) {
  369. typedef typename ::TCompactTrieKeySelector<T>::TKeyBuf TSBuffer;
  370. for (TConstIterator it = Begin(); it != End(); ++it) {
  371. os << TSBuffer((*it).first.data(), (*it).first.size()) << "\t" << (*it).second << Endl;
  372. }
  373. }
  374. template <class T, class D, class S>
  375. bool TCompactTrie<T, D, S>::FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixLen, TData* value, bool* hasNext) const {
  376. const char* valuepos = nullptr;
  377. size_t tempPrefixLen = 0;
  378. bool tempHasNext;
  379. bool found = LookupLongestPrefix(key, keylen, tempPrefixLen, valuepos, tempHasNext);
  380. if (prefixLen)
  381. *prefixLen = tempPrefixLen;
  382. if (found && value)
  383. Packer.UnpackLeaf(valuepos, *value);
  384. if (hasNext)
  385. *hasNext = tempHasNext;
  386. return found;
  387. }
  388. template <class T, class D, class S>
  389. bool TCompactTrie<T, D, S>::LookupLongestPrefix(const TSymbol* key, size_t keylen, size_t& prefixLen, const char*& valuepos, bool& hasNext) const {
  390. using namespace NCompactTrie;
  391. const char* datapos = DataHolder.AsCharPtr();
  392. size_t len = DataHolder.Length();
  393. prefixLen = 0;
  394. hasNext = false;
  395. bool found = false;
  396. if (EmptyValue) {
  397. valuepos = EmptyValue;
  398. found = true;
  399. }
  400. if (!key || !len)
  401. return found;
  402. const char* const dataend = datapos + len;
  403. const T* keyend = key + keylen;
  404. while (key != keyend) {
  405. T label = *(key++);
  406. for (i64 i = (i64)ExtraBits<TSymbol>(); i >= 0; i -= 8) {
  407. const char flags = LeapByte(datapos, dataend, (char)(label >> i));
  408. if (!datapos) {
  409. return found; // no such arc
  410. }
  411. Y_ASSERT(datapos <= dataend);
  412. if ((flags & MT_FINAL)) {
  413. prefixLen = keylen - (keyend - key) - (i ? 1 : 0);
  414. valuepos = datapos;
  415. hasNext = flags & MT_NEXT;
  416. found = true;
  417. if (!i && key == keyend) { // last byte, and got a match
  418. return found;
  419. }
  420. datapos += Packer.SkipLeaf(datapos); // skip intermediate leaf nodes
  421. }
  422. if (!(flags & MT_NEXT)) {
  423. return found; // no further way
  424. }
  425. }
  426. }
  427. return found;
  428. }
  429. template <class T, class D, class S>
  430. void TCompactTrie<T, D, S>::LookupPhrases(
  431. const char* datapos, size_t len, const TSymbol* key, size_t keylen,
  432. TVector<TPhraseMatch>& matches, TSymbol separator) const {
  433. using namespace NCompactTrie;
  434. matches.clear();
  435. if (!key || !len)
  436. return;
  437. const T* const keystart = key;
  438. const T* const keyend = key + keylen;
  439. const char* const dataend = datapos + len;
  440. while (datapos && key != keyend) {
  441. T label = *(key++);
  442. const char* value = nullptr;
  443. if (!Advance(datapos, dataend, value, label, Packer)) {
  444. return;
  445. }
  446. if (value && (key == keyend || *key == separator)) {
  447. size_t matchlength = (size_t)(key - keystart);
  448. D data;
  449. Packer.UnpackLeaf(value, data);
  450. matches.push_back(TPhraseMatch(matchlength, data));
  451. }
  452. }
  453. }
  454. // TCompactTrieHolder
  455. template <class T, class D, class S>
  456. TCompactTrieHolder<T, D, S>::TCompactTrieHolder(IInputStream& is, size_t len)
  457. : Storage(new char[len])
  458. {
  459. if (is.Load(Storage.Get(), len) != len) {
  460. ythrow yexception() << "bad data load";
  461. }
  462. TBase::Init(Storage.Get(), len);
  463. }
  464. //----------------------------------------------------------------------------------------------------------------
  465. // TCompactTrie::TConstIterator
  466. template <class T, class D, class S>
  467. TCompactTrie<T, D, S>::TConstIterator::TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, bool atend, TPacker packer)
  468. : Packer(packer)
  469. , Impl(new TOpaqueTrieIterator(trie, emptyValue, atend))
  470. {
  471. }
  472. template <class T, class D, class S>
  473. TCompactTrie<T, D, S>::TConstIterator::TConstIterator(const TOpaqueTrie& trie, const char* emptyValue, const TKeyBuf& key, TPacker packer)
  474. : Packer(packer)
  475. , Impl(new TOpaqueTrieIterator(trie, emptyValue, true))
  476. {
  477. Impl->UpperBound<TSymbol>(key);
  478. }
  479. template <class T, class D, class S>
  480. bool TCompactTrie<T, D, S>::TConstIterator::operator==(const TConstIterator& other) const {
  481. if (!Impl)
  482. return !other.Impl;
  483. if (!other.Impl)
  484. return false;
  485. return *Impl == *other.Impl;
  486. }
  487. template <class T, class D, class S>
  488. bool TCompactTrie<T, D, S>::TConstIterator::operator!=(const TConstIterator& other) const {
  489. return !operator==(other);
  490. }
  491. template <class T, class D, class S>
  492. typename TCompactTrie<T, D, S>::TConstIterator& TCompactTrie<T, D, S>::TConstIterator::operator++() {
  493. Impl->Forward();
  494. return *this;
  495. }
  496. template <class T, class D, class S>
  497. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::TConstIterator::operator++(int /*unused*/) {
  498. TConstIterator copy(*this);
  499. Impl->Forward();
  500. return copy;
  501. }
  502. template <class T, class D, class S>
  503. typename TCompactTrie<T, D, S>::TConstIterator& TCompactTrie<T, D, S>::TConstIterator::operator--() {
  504. Impl->Backward();
  505. return *this;
  506. }
  507. template <class T, class D, class S>
  508. typename TCompactTrie<T, D, S>::TConstIterator TCompactTrie<T, D, S>::TConstIterator::operator--(int /*unused*/) {
  509. TConstIterator copy(*this);
  510. Impl->Backward();
  511. return copy;
  512. }
  513. template <class T, class D, class S>
  514. typename TCompactTrie<T, D, S>::TValueType TCompactTrie<T, D, S>::TConstIterator::operator*() {
  515. return TValueType(GetKey(), GetValue());
  516. }
  517. template <class T, class D, class S>
  518. typename TCompactTrie<T, D, S>::TKey TCompactTrie<T, D, S>::TConstIterator::GetKey() const {
  519. return Impl->GetKey<TSymbol>();
  520. }
  521. template <class T, class D, class S>
  522. size_t TCompactTrie<T, D, S>::TConstIterator::GetKeySize() const {
  523. return Impl->MeasureKey<TSymbol>();
  524. }
  525. template <class T, class D, class S>
  526. const char* TCompactTrie<T, D, S>::TConstIterator::GetValuePtr() const {
  527. return Impl->GetValuePtr();
  528. }
  529. template <class T, class D, class S>
  530. typename TCompactTrie<T, D, S>::TData TCompactTrie<T, D, S>::TConstIterator::GetValue() const {
  531. D data;
  532. GetValue(data);
  533. return data;
  534. }
  535. template <class T, class D, class S>
  536. void TCompactTrie<T, D, S>::TConstIterator::GetValue(typename TCompactTrie<T, D, S>::TData& data) const {
  537. const char* ptr = GetValuePtr();
  538. if (ptr) {
  539. Packer.UnpackLeaf(ptr, data);
  540. } else {
  541. data = typename TCompactTrie<T, D, S>::TData();
  542. }
  543. }