comptrie_builder.inl 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. #pragma once
  2. #include "comptrie_impl.h"
  3. #include "comptrie_trie.h"
  4. #include "make_fast_layout.h"
  5. #include "array_with_size.h"
  6. #include <library/cpp/containers/compact_vector/compact_vector.h>
  7. #include <util/memory/alloc.h>
  8. #include <util/memory/blob.h>
  9. #include <util/memory/pool.h>
  10. #include <util/memory/tempbuf.h>
  11. #include <util/memory/smallobj.h>
  12. #include <util/generic/algorithm.h>
  13. #include <util/generic/buffer.h>
  14. #include <util/generic/strbuf.h>
  15. #include <util/system/align.h>
  16. #include <util/stream/buffer.h>
  17. #define CONSTEXPR_MAX2(a, b) (a) > (b) ? (a) : (b)
  18. #define CONSTEXPR_MAX3(a, b, c) CONSTEXPR_MAX2(CONSTEXPR_MAX2(a, b), c)
  19. // TCompactTrieBuilder::TCompactTrieBuilderImpl
  20. template <class T, class D, class S>
  21. class TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl {
  22. protected:
  23. TMemoryPool Pool;
  24. size_t PayloadSize;
  25. THolder<TFixedSizeAllocator> NodeAllocator;
  26. class TNode;
  27. class TArc;
  28. TNode* Root;
  29. TCompactTrieBuilderFlags Flags;
  30. size_t EntryCount;
  31. size_t NodeCount;
  32. TPacker Packer;
  33. enum EPayload {
  34. DATA_ABSENT,
  35. DATA_INSIDE,
  36. DATA_MALLOCED,
  37. DATA_IN_MEMPOOL,
  38. };
  39. protected:
  40. void ConvertSymbolArrayToChar(const TSymbol* key, size_t keylen, TTempBuf& buf, size_t ckeylen) const;
  41. void NodeLinkTo(TNode* thiz, const TBlob& label, TNode* node);
  42. TNode* NodeForwardAdd(TNode* thiz, const char* label, size_t len, size_t& passed, size_t* nodeCount);
  43. bool FindEntryImpl(const char* key, size_t keylen, TData* value) const;
  44. bool FindLongestPrefixImpl(const char* keyptr, size_t keylen, size_t* prefixLen, TData* value) const;
  45. size_t NodeMeasureSubtree(TNode* thiz) const;
  46. ui64 NodeSaveSubtree(TNode* thiz, IOutputStream& os) const;
  47. ui64 NodeSaveSubtreeAndDestroy(TNode* thiz, IOutputStream& osy);
  48. void NodeBufferSubtree(TNode* thiz);
  49. size_t NodeMeasureLeafValue(TNode* thiz) const;
  50. ui64 NodeSaveLeafValue(TNode* thiz, IOutputStream& os) const;
  51. virtual ui64 ArcMeasure(const TArc* thiz, size_t leftsize, size_t rightsize) const;
  52. virtual ui64 ArcSaveSelf(const TArc* thiz, IOutputStream& os) const;
  53. ui64 ArcSave(const TArc* thiz, IOutputStream& os) const;
  54. ui64 ArcSaveAndDestroy(const TArc* thiz, IOutputStream& os);
  55. public:
  56. TCompactTrieBuilderImpl(TCompactTrieBuilderFlags flags, TPacker packer, IAllocator* alloc);
  57. virtual ~TCompactTrieBuilderImpl();
  58. void DestroyNode(TNode* node);
  59. void NodeReleasePayload(TNode* thiz);
  60. char* AddEntryForData(const TSymbol* key, size_t keylen, size_t dataLen, bool& isNewAddition);
  61. TNode* AddEntryForSomething(const TSymbol* key, size_t keylen, bool& isNewAddition);
  62. bool AddEntry(const TSymbol* key, size_t keylen, const TData& value);
  63. bool AddEntryPtr(const TSymbol* key, size_t keylen, const char* value);
  64. bool AddSubtreeInFile(const TSymbol* key, size_t keylen, const TString& fileName);
  65. bool AddSubtreeInBuffer(const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer);
  66. bool FindEntry(const TSymbol* key, size_t keylen, TData* value) const;
  67. bool FindLongestPrefix(const TSymbol* key, size_t keylen, size_t* prefixlen, TData* value) const;
  68. size_t Save(IOutputStream& os) const;
  69. size_t SaveAndDestroy(IOutputStream& os);
  70. void Clear();
  71. // lies if some key was added at least twice
  72. size_t GetEntryCount() const;
  73. size_t GetNodeCount() const;
  74. size_t MeasureByteSize() const {
  75. return NodeMeasureSubtree(Root);
  76. }
  77. };
  78. template <class T, class D, class S>
  79. class TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TArc {
  80. public:
  81. TBlob Label;
  82. TNode* Node;
  83. mutable size_t LeftOffset;
  84. mutable size_t RightOffset;
  85. TArc(const TBlob& lbl, TNode* nd);
  86. };
  87. template <class T, class D, class S>
  88. class TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode {
  89. public:
  90. typedef typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl TBuilderImpl;
  91. typedef typename TBuilderImpl::TArc TArc;
  92. struct ISubtree {
  93. virtual ~ISubtree() = default;
  94. virtual bool IsLast() const = 0;
  95. virtual ui64 Measure(const TBuilderImpl* builder) const = 0;
  96. virtual ui64 Save(const TBuilderImpl* builder, IOutputStream& os) const = 0;
  97. virtual ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) = 0;
  98. virtual void Destroy(TBuilderImpl*) { }
  99. // Tries to find key in subtree.
  100. // Returns next node to find the key in (to avoid recursive calls)
  101. // If it has end result, writes it to @value and @result arguments and returns nullptr
  102. virtual const TNode* Find(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const = 0;
  103. virtual const TNode* FindLongestPrefix(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const = 0;
  104. };
  105. class TArcSet: public ISubtree, public TCompactVector<TArc> {
  106. public:
  107. typedef typename TCompactVector<TArc>::iterator iterator;
  108. typedef typename TCompactVector<TArc>::const_iterator const_iterator;
  109. TArcSet() {
  110. Y_ASSERT(reinterpret_cast<ISubtree*>(this) == static_cast<void*>(this)); // This assumption is used in TNode::Subtree()
  111. }
  112. iterator Find(char ch);
  113. const_iterator Find(char ch) const;
  114. void Add(const TBlob& s, TNode* node);
  115. bool IsLast() const override {
  116. return this->Empty();
  117. }
  118. const TNode* Find(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override;
  119. const TNode* FindLongestPrefix(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override {
  120. return Find(key, value, result, packer);
  121. }
  122. ui64 Measure(const TBuilderImpl* builder) const override {
  123. return MeasureRange(builder, 0, this->size());
  124. }
  125. ui64 MeasureRange(const TBuilderImpl* builder, size_t from, size_t to) const {
  126. if (from >= to)
  127. return 0;
  128. size_t median = (from + to) / 2;
  129. size_t leftsize = (size_t)MeasureRange(builder, from, median);
  130. size_t rightsize = (size_t)MeasureRange(builder, median + 1, to);
  131. return builder->ArcMeasure(&(*this)[median], leftsize, rightsize);
  132. }
  133. ui64 Save(const TBuilderImpl* builder, IOutputStream& os) const override {
  134. return SaveRange(builder, 0, this->size(), os);
  135. }
  136. ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) override {
  137. ui64 result = SaveRangeAndDestroy(builder, 0, this->size(), os);
  138. Destroy(builder);
  139. return result;
  140. }
  141. ui64 SaveRange(const TBuilderImpl* builder, size_t from, size_t to, IOutputStream& os) const {
  142. if (from >= to)
  143. return 0;
  144. size_t median = (from + to) / 2;
  145. ui64 written = builder->ArcSave(&(*this)[median], os);
  146. written += SaveRange(builder, from, median, os);
  147. written += SaveRange(builder, median + 1, to, os);
  148. return written;
  149. }
  150. ui64 SaveRangeAndDestroy(TBuilderImpl* builder, size_t from, size_t to, IOutputStream& os) {
  151. if (from >= to)
  152. return 0;
  153. size_t median = (from + to) / 2;
  154. ui64 written = builder->ArcSaveAndDestroy(&(*this)[median], os);
  155. written += SaveRangeAndDestroy(builder, from, median, os);
  156. written += SaveRangeAndDestroy(builder, median + 1, to, os);
  157. return written;
  158. }
  159. void Destroy(TBuilderImpl* builder) override {
  160. // Delete all nodes down the stream.
  161. for (iterator it = this->begin(); it != this->end(); ++it) {
  162. builder->DestroyNode(it->Node);
  163. }
  164. this->clear();
  165. }
  166. ~TArcSet() override {
  167. Y_ASSERT(this->empty());
  168. }
  169. };
  170. struct TBufferedSubtree: public ISubtree {
  171. TArrayWithSizeHolder<char> Buffer;
  172. TBufferedSubtree() {
  173. Y_ASSERT(reinterpret_cast<ISubtree*>(this) == static_cast<void*>(this)); // This assumption is used in TNode::Subtree()
  174. }
  175. bool IsLast() const override {
  176. return Buffer.Empty();
  177. }
  178. const TNode* Find(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override {
  179. if (Buffer.Empty()) {
  180. result = false;
  181. return nullptr;
  182. }
  183. TCompactTrie<char, D, S> trie(Buffer.Get(), Buffer.Size(), packer);
  184. result = trie.Find(key.data(), key.size(), value);
  185. return nullptr;
  186. }
  187. const TNode* FindLongestPrefix(TStringBuf& key, TData* value, bool& result, const TPacker& packer) const override {
  188. if (Buffer.Empty()) {
  189. result = false;
  190. return nullptr;
  191. }
  192. TCompactTrie<char, D, S> trie(Buffer.Get(), Buffer.Size(), packer);
  193. size_t prefixLen = 0;
  194. result = trie.FindLongestPrefix(key.data(), key.size(), &prefixLen, value);
  195. key = key.SubStr(prefixLen);
  196. return nullptr;
  197. }
  198. ui64 Measure(const TBuilderImpl*) const override {
  199. return Buffer.Size();
  200. }
  201. ui64 Save(const TBuilderImpl*, IOutputStream& os) const override {
  202. os.Write(Buffer.Get(), Buffer.Size());
  203. return Buffer.Size();
  204. }
  205. ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) override {
  206. ui64 result = Save(builder, os);
  207. TArrayWithSizeHolder<char>().Swap(Buffer);
  208. return result;
  209. }
  210. };
  211. struct TSubtreeInFile: public ISubtree {
  212. struct TData {
  213. TString FileName;
  214. ui64 Size;
  215. };
  216. THolder<TData> Data;
  217. TSubtreeInFile(const TString& fileName) {
  218. // stupid API
  219. TFile file(fileName, RdOnly);
  220. i64 size = file.GetLength();
  221. if (size < 0)
  222. ythrow yexception() << "unable to get file " << fileName.Quote() << " size for unknown reason";
  223. Data.Reset(new TData);
  224. Data->FileName = fileName;
  225. Data->Size = size;
  226. Y_ASSERT(reinterpret_cast<ISubtree*>(this) == static_cast<void*>(this)); // This assumption is used in TNode::Subtree()
  227. }
  228. bool IsLast() const override {
  229. return Data->Size == 0;
  230. }
  231. const TNode* Find(TStringBuf& key, typename TCompactTrieBuilder::TData* value, bool& result, const TPacker& packer) const override {
  232. if (!Data) {
  233. result = false;
  234. return nullptr;
  235. }
  236. TCompactTrie<char, D, S> trie(TBlob::FromFile(Data->FileName), packer);
  237. result = trie.Find(key.data(), key.size(), value);
  238. return nullptr;
  239. }
  240. const TNode* FindLongestPrefix(TStringBuf& key, typename TCompactTrieBuilder::TData* value, bool& result, const TPacker& packer) const override {
  241. if (!Data) {
  242. result = false;
  243. return nullptr;
  244. }
  245. TCompactTrie<char, D, S> trie(TBlob::FromFile(Data->FileName), packer);
  246. size_t prefixLen = 0;
  247. result = trie.FindLongestPrefix(key.data(), key.size(), &prefixLen, value);
  248. key = key.SubStr(prefixLen);
  249. return nullptr;
  250. }
  251. ui64 Measure(const TBuilderImpl*) const override {
  252. return Data->Size;
  253. }
  254. ui64 Save(const TBuilderImpl*, IOutputStream& os) const override {
  255. TUnbufferedFileInput is(Data->FileName);
  256. ui64 written = TransferData(&is, &os);
  257. if (written != Data->Size)
  258. ythrow yexception() << "file " << Data->FileName.Quote() << " size changed";
  259. return written;
  260. }
  261. ui64 SaveAndDestroy(TBuilderImpl* builder, IOutputStream& os) override {
  262. return Save(builder, os);
  263. }
  264. };
  265. union {
  266. char ArcsData[CONSTEXPR_MAX3(sizeof(TArcSet), sizeof(TBufferedSubtree), sizeof(TSubtreeInFile))];
  267. union {
  268. void* Data1;
  269. long long int Data2;
  270. } Aligner;
  271. };
  272. inline ISubtree* Subtree() {
  273. return reinterpret_cast<ISubtree*>(ArcsData);
  274. }
  275. inline const ISubtree* Subtree() const {
  276. return reinterpret_cast<const ISubtree*>(ArcsData);
  277. }
  278. EPayload PayloadType;
  279. inline const char* PayloadPtr() const {
  280. return ((const char*) this) + sizeof(TNode);
  281. }
  282. inline char* PayloadPtr() {
  283. return ((char*) this) + sizeof(TNode);
  284. }
  285. // *Payload()
  286. inline const char*& PayloadAsPtr() const {
  287. const char** payload = (const char**) PayloadPtr();
  288. return *payload;
  289. }
  290. inline char*& PayloadAsPtr() {
  291. char** payload = (char**) PayloadPtr();
  292. return *payload;
  293. }
  294. inline const char* GetPayload() const {
  295. switch (PayloadType) {
  296. case DATA_INSIDE:
  297. return PayloadPtr();
  298. case DATA_MALLOCED:
  299. case DATA_IN_MEMPOOL:
  300. return PayloadAsPtr();
  301. case DATA_ABSENT:
  302. default:
  303. abort();
  304. }
  305. }
  306. inline char* GetPayload() {
  307. const TNode* thiz = this;
  308. return const_cast<char*>(thiz->GetPayload()); // const_cast is to avoid copy-paste style
  309. }
  310. bool IsFinal() const {
  311. return PayloadType != DATA_ABSENT;
  312. }
  313. bool IsLast() const {
  314. return Subtree()->IsLast();
  315. }
  316. inline void* operator new(size_t, TFixedSizeAllocator& pool) {
  317. return pool.Allocate();
  318. }
  319. inline void operator delete(void* ptr, TFixedSizeAllocator& pool) noexcept {
  320. pool.Release(ptr);
  321. }
  322. TNode()
  323. : PayloadType(DATA_ABSENT)
  324. {
  325. new (Subtree()) TArcSet;
  326. }
  327. ~TNode() {
  328. Subtree()->~ISubtree();
  329. Y_ASSERT(PayloadType == DATA_ABSENT);
  330. }
  331. };
  332. // TCompactTrieBuilder
  333. template <class T, class D, class S>
  334. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilder(TCompactTrieBuilderFlags flags, TPacker packer, IAllocator* alloc)
  335. : Impl(new TCompactTrieBuilderImpl(flags, packer, alloc))
  336. {
  337. }
  338. template <class T, class D, class S>
  339. bool TCompactTrieBuilder<T, D, S>::Add(const TSymbol* key, size_t keylen, const TData& value) {
  340. return Impl->AddEntry(key, keylen, value);
  341. }
  342. template <class T, class D, class S>
  343. bool TCompactTrieBuilder<T, D, S>::AddPtr(const TSymbol* key, size_t keylen, const char* value) {
  344. return Impl->AddEntryPtr(key, keylen, value);
  345. }
  346. template <class T, class D, class S>
  347. bool TCompactTrieBuilder<T, D, S>::AddSubtreeInFile(const TSymbol* key, size_t keylen, const TString& fileName) {
  348. return Impl->AddSubtreeInFile(key, keylen, fileName);
  349. }
  350. template <class T, class D, class S>
  351. bool TCompactTrieBuilder<T, D, S>::AddSubtreeInBuffer(const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer) {
  352. return Impl->AddSubtreeInBuffer(key, keylen, std::move(buffer));
  353. }
  354. template <class T, class D, class S>
  355. bool TCompactTrieBuilder<T, D, S>::Find(const TSymbol* key, size_t keylen, TData* value) const {
  356. return Impl->FindEntry(key, keylen, value);
  357. }
  358. template <class T, class D, class S>
  359. bool TCompactTrieBuilder<T, D, S>::FindLongestPrefix(
  360. const TSymbol* key, size_t keylen, size_t* prefixlen, TData* value) const {
  361. return Impl->FindLongestPrefix(key, keylen, prefixlen, value);
  362. }
  363. template <class T, class D, class S>
  364. size_t TCompactTrieBuilder<T, D, S>::Save(IOutputStream& os) const {
  365. return Impl->Save(os);
  366. }
  367. template <class T, class D, class S>
  368. size_t TCompactTrieBuilder<T, D, S>::SaveAndDestroy(IOutputStream& os) {
  369. return Impl->SaveAndDestroy(os);
  370. }
  371. template <class T, class D, class S>
  372. void TCompactTrieBuilder<T, D, S>::Clear() {
  373. Impl->Clear();
  374. }
  375. template <class T, class D, class S>
  376. size_t TCompactTrieBuilder<T, D, S>::GetEntryCount() const {
  377. return Impl->GetEntryCount();
  378. }
  379. template <class T, class D, class S>
  380. size_t TCompactTrieBuilder<T, D, S>::GetNodeCount() const {
  381. return Impl->GetNodeCount();
  382. }
  383. // TCompactTrieBuilder::TCompactTrieBuilderImpl
  384. template <class T, class D, class S>
  385. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TCompactTrieBuilderImpl(TCompactTrieBuilderFlags flags, TPacker packer, IAllocator* alloc)
  386. : Pool(1000000, TMemoryPool::TLinearGrow::Instance(), alloc)
  387. , PayloadSize(sizeof(void*)) // XXX: find better value
  388. , NodeAllocator(new TFixedSizeAllocator(sizeof(TNode) + PayloadSize, alloc))
  389. , Flags(flags)
  390. , EntryCount(0)
  391. , NodeCount(1)
  392. , Packer(packer)
  393. {
  394. Root = new (*NodeAllocator) TNode;
  395. }
  396. template <class T, class D, class S>
  397. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::~TCompactTrieBuilderImpl() {
  398. DestroyNode(Root);
  399. }
  400. template <class T, class D, class S>
  401. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ConvertSymbolArrayToChar(
  402. const TSymbol* key, size_t keylen, TTempBuf& buf, size_t buflen) const {
  403. char* ckeyptr = buf.Data();
  404. for (size_t i = 0; i < keylen; ++i) {
  405. TSymbol label = key[i];
  406. for (int j = (int)NCompactTrie::ExtraBits<TSymbol>(); j >= 0; j -= 8) {
  407. Y_ASSERT(ckeyptr < buf.Data() + buflen);
  408. *(ckeyptr++) = (char)(label >> j);
  409. }
  410. }
  411. buf.Proceed(buflen);
  412. Y_ASSERT(ckeyptr == buf.Data() + buf.Filled());
  413. }
  414. template <class T, class D, class S>
  415. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::DestroyNode(TNode* thiz) {
  416. thiz->Subtree()->Destroy(this);
  417. NodeReleasePayload(thiz);
  418. thiz->~TNode();
  419. NodeAllocator->Release(thiz);
  420. }
  421. template <class T, class D, class S>
  422. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeReleasePayload(TNode* thiz) {
  423. switch (thiz->PayloadType) {
  424. case DATA_ABSENT:
  425. case DATA_INSIDE:
  426. case DATA_IN_MEMPOOL:
  427. break;
  428. case DATA_MALLOCED:
  429. delete[] thiz->PayloadAsPtr();
  430. break;
  431. default:
  432. abort();
  433. }
  434. thiz->PayloadType = DATA_ABSENT;
  435. }
  436. template <class T, class D, class S>
  437. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntry(
  438. const TSymbol* key, size_t keylen, const TData& value) {
  439. size_t datalen = Packer.MeasureLeaf(value);
  440. bool isNewAddition = false;
  441. char* place = AddEntryForData(key, keylen, datalen, isNewAddition);
  442. Packer.PackLeaf(place, value, datalen);
  443. return isNewAddition;
  444. }
  445. template <class T, class D, class S>
  446. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntryPtr(
  447. const TSymbol* key, size_t keylen, const char* value) {
  448. size_t datalen = Packer.SkipLeaf(value);
  449. bool isNewAddition = false;
  450. char* place = AddEntryForData(key, keylen, datalen, isNewAddition);
  451. memcpy(place, value, datalen);
  452. return isNewAddition;
  453. }
  454. template <class T, class D, class S>
  455. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddSubtreeInFile(
  456. const TSymbol* key, size_t keylen, const TString& fileName) {
  457. typedef typename TNode::ISubtree ISubtree;
  458. typedef typename TNode::TSubtreeInFile TSubtreeInFile;
  459. bool isNewAddition = false;
  460. TNode* node = AddEntryForSomething(key, keylen, isNewAddition);
  461. node->Subtree()->Destroy(this);
  462. node->Subtree()->~ISubtree();
  463. new (node->Subtree()) TSubtreeInFile(fileName);
  464. return isNewAddition;
  465. }
  466. template <class T, class D, class S>
  467. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddSubtreeInBuffer(
  468. const TSymbol* key, size_t keylen, TArrayWithSizeHolder<char>&& buffer) {
  469. typedef typename TNode::TBufferedSubtree TBufferedSubtree;
  470. bool isNewAddition = false;
  471. TNode* node = AddEntryForSomething(key, keylen, isNewAddition);
  472. node->Subtree()->Destroy(this);
  473. node->Subtree()->~ISubtree();
  474. auto subtree = new (node->Subtree()) TBufferedSubtree();
  475. subtree->Buffer.Swap(buffer);
  476. return isNewAddition;
  477. }
  478. template <class T, class D, class S>
  479. typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode*
  480. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntryForSomething(
  481. const TSymbol* key, size_t keylen, bool& isNewAddition) {
  482. using namespace NCompactTrie;
  483. EntryCount++;
  484. if (Flags & CTBF_VERBOSE)
  485. ShowProgress(EntryCount);
  486. TNode* current = Root;
  487. size_t passed;
  488. // Special case of empty key: replace it by 1-byte "\0" key.
  489. size_t ckeylen = keylen ? keylen * sizeof(TSymbol) : 1;
  490. TTempBuf ckeybuf(ckeylen);
  491. if (keylen == 0) {
  492. ckeybuf.Append("\0", 1);
  493. } else {
  494. ConvertSymbolArrayToChar(key, keylen, ckeybuf, ckeylen);
  495. }
  496. char* ckey = ckeybuf.Data();
  497. TNode* next;
  498. while ((ckeylen > 0) && (next = NodeForwardAdd(current, ckey, ckeylen, passed, &NodeCount)) != nullptr) {
  499. current = next;
  500. ckeylen -= passed;
  501. ckey += passed;
  502. }
  503. if (ckeylen != 0) {
  504. //new leaf
  505. NodeCount++;
  506. TNode* leaf = new (*NodeAllocator) TNode();
  507. NodeLinkTo(current, TBlob::Copy(ckey, ckeylen), leaf);
  508. current = leaf;
  509. }
  510. isNewAddition = (current->PayloadType == DATA_ABSENT);
  511. if ((Flags & CTBF_UNIQUE) && !isNewAddition)
  512. ythrow yexception() << "Duplicate key";
  513. return current;
  514. }
  515. template <class T, class D, class S>
  516. char* TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::AddEntryForData(const TSymbol* key, size_t keylen,
  517. size_t datalen, bool& isNewAddition) {
  518. TNode* current = AddEntryForSomething(key, keylen, isNewAddition);
  519. NodeReleasePayload(current);
  520. if (datalen <= PayloadSize) {
  521. current->PayloadType = DATA_INSIDE;
  522. } else if (Flags & CTBF_PREFIX_GROUPED) {
  523. current->PayloadType = DATA_MALLOCED;
  524. current->PayloadAsPtr() = new char[datalen];
  525. } else {
  526. current->PayloadType = DATA_IN_MEMPOOL;
  527. current->PayloadAsPtr() = (char*) Pool.Allocate(datalen); // XXX: allocate unaligned
  528. }
  529. return current->GetPayload();
  530. }
  531. template <class T, class D, class S>
  532. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindEntry(const TSymbol* key, size_t keylen, TData* value) const {
  533. using namespace NCompactTrie;
  534. if (!keylen) {
  535. const char zero = '\0';
  536. return FindEntryImpl(&zero, 1, value);
  537. } else {
  538. size_t ckeylen = keylen * sizeof(TSymbol);
  539. TTempBuf ckeybuf(ckeylen);
  540. ConvertSymbolArrayToChar(key, keylen, ckeybuf, ckeylen);
  541. return FindEntryImpl(ckeybuf.Data(), ckeylen, value);
  542. }
  543. }
  544. template <class T, class D, class S>
  545. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindEntryImpl(const char* keyptr, size_t keylen, TData* value) const {
  546. const TNode* node = Root;
  547. bool result = false;
  548. TStringBuf key(keyptr, keylen);
  549. while (key && (node = node->Subtree()->Find(key, value, result, Packer))) {
  550. }
  551. return result;
  552. }
  553. template <class T, class D, class S>
  554. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindLongestPrefix(
  555. const TSymbol* key, size_t keylen, size_t* prefixlen, TData* value) const {
  556. using namespace NCompactTrie;
  557. if (!keylen) {
  558. const char zero = '\0';
  559. const bool ret = FindLongestPrefixImpl(&zero, 1, prefixlen, value);
  560. if (ret && prefixlen)
  561. *prefixlen = 0; // empty key found
  562. return ret;
  563. } else {
  564. size_t ckeylen = keylen * sizeof(TSymbol);
  565. TTempBuf ckeybuf(ckeylen);
  566. ConvertSymbolArrayToChar(key, keylen, ckeybuf, ckeylen);
  567. bool ret = FindLongestPrefixImpl(ckeybuf.Data(), ckeylen, prefixlen, value);
  568. if (ret && prefixlen && *prefixlen == 1 && ckeybuf.Data()[0] == '\0')
  569. *prefixlen = 0; // if we have found empty key, set prefixlen to zero
  570. else if (!ret) // try to find value with empty key, because empty key is prefix of a every key
  571. ret = FindLongestPrefix(nullptr, 0, prefixlen, value);
  572. if (ret && prefixlen)
  573. *prefixlen /= sizeof(TSymbol);
  574. return ret;
  575. }
  576. }
  577. template <class T, class D, class S>
  578. bool TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::FindLongestPrefixImpl(const char* keyptr, size_t keylen, size_t* prefixLen, TData* value) const {
  579. const TNode* node = Root;
  580. const TNode* lastFinalNode = nullptr;
  581. bool endResult = false;
  582. TStringBuf key(keyptr, keylen);
  583. TStringBuf keyTail = key;
  584. TStringBuf lastFinalKeyTail;
  585. while (keyTail && (node = node->Subtree()->FindLongestPrefix(keyTail, value, endResult, Packer))) {
  586. if (endResult) // no more ways to find prefix and prefix has been found
  587. break;
  588. if (node->IsFinal()) {
  589. lastFinalNode = node;
  590. lastFinalKeyTail = keyTail;
  591. }
  592. }
  593. if (!endResult && lastFinalNode) {
  594. if (value)
  595. Packer.UnpackLeaf(lastFinalNode->GetPayload(), *value);
  596. keyTail = lastFinalKeyTail;
  597. endResult = true;
  598. }
  599. if (endResult && prefixLen)
  600. *prefixLen = keyTail ? key.size() - keyTail.size() : key.size();
  601. return endResult;
  602. }
  603. template <class T, class D, class S>
  604. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::Clear() {
  605. DestroyNode(Root);
  606. Pool.Clear();
  607. NodeAllocator.Reset(new TFixedSizeAllocator(sizeof(TNode) + PayloadSize, TDefaultAllocator::Instance()));
  608. Root = new (*NodeAllocator) TNode;
  609. EntryCount = 0;
  610. NodeCount = 1;
  611. }
  612. template <class T, class D, class S>
  613. size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::Save(IOutputStream& os) const {
  614. const size_t len = NodeMeasureSubtree(Root);
  615. if (len != NodeSaveSubtree(Root, os))
  616. ythrow yexception() << "something wrong";
  617. return len;
  618. }
  619. template <class T, class D, class S>
  620. size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::SaveAndDestroy(IOutputStream& os) {
  621. const size_t len = NodeMeasureSubtree(Root);
  622. if (len != NodeSaveSubtreeAndDestroy(Root, os))
  623. ythrow yexception() << "something wrong";
  624. return len;
  625. }
  626. template <class T, class D, class S>
  627. size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::GetEntryCount() const {
  628. return EntryCount;
  629. }
  630. template <class T, class D, class S>
  631. size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::GetNodeCount() const {
  632. return NodeCount;
  633. }
  634. template <class T, class D, class S>
  635. typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode*
  636. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeForwardAdd(
  637. TNode* thiz, const char* label, size_t len, size_t& passed, size_t* nodeCount) {
  638. typename TNode::TArcSet* arcSet = dynamic_cast<typename TNode::TArcSet*>(thiz->Subtree());
  639. if (!arcSet)
  640. ythrow yexception() << "Bad input order - expected input strings to be prefix-grouped.";
  641. typename TNode::TArcSet::iterator it = arcSet->Find(*label);
  642. if (it != arcSet->end()) {
  643. const char* arcLabel = it->Label.AsCharPtr();
  644. size_t arcLabelLen = it->Label.Length();
  645. for (passed = 0; (passed < len) && (passed < arcLabelLen) && (label[passed] == arcLabel[passed]); ++passed) {
  646. //just count
  647. }
  648. if (passed < arcLabelLen) {
  649. (*nodeCount)++;
  650. TNode* node = new (*NodeAllocator) TNode();
  651. NodeLinkTo(node, it->Label.SubBlob(passed, arcLabelLen), it->Node);
  652. it->Node = node;
  653. it->Label = it->Label.SubBlob(passed);
  654. }
  655. return it->Node;
  656. }
  657. return nullptr;
  658. }
  659. template <class T, class D, class S>
  660. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeLinkTo(TNode* thiz, const TBlob& label, TNode* node) {
  661. typename TNode::TArcSet* arcSet = dynamic_cast<typename TNode::TArcSet*>(thiz->Subtree());
  662. if (!arcSet)
  663. ythrow yexception() << "Bad input order - expected input strings to be prefix-grouped.";
  664. // Buffer the node at the last arc
  665. if ((Flags & CTBF_PREFIX_GROUPED) && !arcSet->empty())
  666. NodeBufferSubtree(arcSet->back().Node);
  667. arcSet->Add(label, node);
  668. }
  669. template <class T, class D, class S>
  670. size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeMeasureSubtree(TNode* thiz) const {
  671. return (size_t)thiz->Subtree()->Measure(this);
  672. }
  673. template <class T, class D, class S>
  674. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeSaveSubtree(TNode* thiz, IOutputStream& os) const {
  675. return thiz->Subtree()->Save(this, os);
  676. }
  677. template <class T, class D, class S>
  678. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeSaveSubtreeAndDestroy(TNode* thiz, IOutputStream& os) {
  679. return thiz->Subtree()->SaveAndDestroy(this, os);
  680. }
  681. template <class T, class D, class S>
  682. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeBufferSubtree(TNode* thiz) {
  683. typedef typename TNode::TArcSet TArcSet;
  684. TArcSet* arcSet = dynamic_cast<TArcSet*>(thiz->Subtree());
  685. if (!arcSet)
  686. return;
  687. size_t bufferLength = (size_t)arcSet->Measure(this);
  688. TArrayWithSizeHolder<char> buffer;
  689. buffer.Resize(bufferLength);
  690. TMemoryOutput bufout(buffer.Get(), buffer.Size());
  691. ui64 written = arcSet->Save(this, bufout);
  692. Y_ASSERT(written == bufferLength);
  693. arcSet->Destroy(this);
  694. arcSet->~TArcSet();
  695. typename TNode::TBufferedSubtree* bufferedArcSet = new (thiz->Subtree()) typename TNode::TBufferedSubtree;
  696. bufferedArcSet->Buffer.Swap(buffer);
  697. }
  698. template <class T, class D, class S>
  699. size_t TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeMeasureLeafValue(TNode* thiz) const {
  700. if (!thiz->IsFinal())
  701. return 0;
  702. return Packer.SkipLeaf(thiz->GetPayload());
  703. }
  704. template <class T, class D, class S>
  705. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::NodeSaveLeafValue(TNode* thiz, IOutputStream& os) const {
  706. if (!thiz->IsFinal())
  707. return 0;
  708. size_t len = Packer.SkipLeaf(thiz->GetPayload());
  709. os.Write(thiz->GetPayload(), len);
  710. return len;
  711. }
  712. // TCompactTrieBuilder::TCompactTrieBuilderImpl::TNode::TArc
  713. template <class T, class D, class S>
  714. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TArc::TArc(const TBlob& lbl, TNode* nd)
  715. : Label(lbl)
  716. , Node(nd)
  717. , LeftOffset(0)
  718. , RightOffset(0)
  719. {}
  720. template <class T, class D, class S>
  721. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcMeasure(
  722. const TArc* thiz, size_t leftsize, size_t rightsize) const {
  723. using namespace NCompactTrie;
  724. size_t coresize = 2 + NodeMeasureLeafValue(thiz->Node); // 2 == (char + flags)
  725. size_t treesize = NodeMeasureSubtree(thiz->Node);
  726. if (thiz->Label.Length() > 0)
  727. treesize += 2 * (thiz->Label.Length() - 1);
  728. // Triple measurements are needed because the space needed to store the offset
  729. // shall be added to the offset itself. Hence three iterations.
  730. size_t leftoffsetsize = leftsize ? MeasureOffset(coresize + treesize) : 0;
  731. size_t rightoffsetsize = rightsize ? MeasureOffset(coresize + treesize + leftsize) : 0;
  732. leftoffsetsize = leftsize ? MeasureOffset(coresize + treesize + leftoffsetsize + rightoffsetsize) : 0;
  733. rightoffsetsize = rightsize ? MeasureOffset(coresize + treesize + leftsize + leftoffsetsize + rightoffsetsize) : 0;
  734. leftoffsetsize = leftsize ? MeasureOffset(coresize + treesize + leftoffsetsize + rightoffsetsize) : 0;
  735. rightoffsetsize = rightsize ? MeasureOffset(coresize + treesize + leftsize + leftoffsetsize + rightoffsetsize) : 0;
  736. coresize += leftoffsetsize + rightoffsetsize;
  737. thiz->LeftOffset = leftsize ? coresize + treesize : 0;
  738. thiz->RightOffset = rightsize ? coresize + treesize + leftsize : 0;
  739. return coresize + treesize + leftsize + rightsize;
  740. }
  741. template <class T, class D, class S>
  742. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcSaveSelf(const TArc* thiz, IOutputStream& os) const {
  743. using namespace NCompactTrie;
  744. ui64 written = 0;
  745. size_t leftoffsetsize = MeasureOffset(thiz->LeftOffset);
  746. size_t rightoffsetsize = MeasureOffset(thiz->RightOffset);
  747. size_t labelLen = thiz->Label.Length();
  748. for (size_t i = 0; i < labelLen; ++i) {
  749. char flags = 0;
  750. if (i == 0) {
  751. flags |= (leftoffsetsize << MT_LEFTSHIFT);
  752. flags |= (rightoffsetsize << MT_RIGHTSHIFT);
  753. }
  754. if (i == labelLen-1) {
  755. if (thiz->Node->IsFinal())
  756. flags |= MT_FINAL;
  757. if (!thiz->Node->IsLast())
  758. flags |= MT_NEXT;
  759. } else {
  760. flags |= MT_NEXT;
  761. }
  762. os.Write(&flags, 1);
  763. os.Write(&thiz->Label.AsCharPtr()[i], 1);
  764. written += 2;
  765. if (i == 0) {
  766. written += ArcSaveOffset(thiz->LeftOffset, os);
  767. written += ArcSaveOffset(thiz->RightOffset, os);
  768. }
  769. }
  770. written += NodeSaveLeafValue(thiz->Node, os);
  771. return written;
  772. }
  773. template <class T, class D, class S>
  774. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcSave(const TArc* thiz, IOutputStream& os) const {
  775. ui64 written = ArcSaveSelf(thiz, os);
  776. written += NodeSaveSubtree(thiz->Node, os);
  777. return written;
  778. }
  779. template <class T, class D, class S>
  780. ui64 TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::ArcSaveAndDestroy(const TArc* thiz, IOutputStream& os) {
  781. ui64 written = ArcSaveSelf(thiz, os);
  782. written += NodeSaveSubtreeAndDestroy(thiz->Node, os);
  783. return written;
  784. }
  785. // TCompactTrieBuilder::TCompactTrieBuilderImpl::TNode::TArcSet
  786. template <class T, class D, class S>
  787. typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::iterator
  788. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Find(char ch) {
  789. using namespace NCompTriePrivate;
  790. iterator it = LowerBound(this->begin(), this->end(), ch, TCmp());
  791. if (it != this->end() && it->Label[0] == (unsigned char)ch) {
  792. return it;
  793. }
  794. return this->end();
  795. }
  796. template <class T, class D, class S>
  797. typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::const_iterator
  798. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Find(char ch) const {
  799. using namespace NCompTriePrivate;
  800. const_iterator it = LowerBound(this->begin(), this->end(), ch, TCmp());
  801. if (it != this->end() && it->Label[0] == (unsigned char)ch) {
  802. return it;
  803. }
  804. return this->end();
  805. }
  806. template <class T, class D, class S>
  807. void TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Add(const TBlob& s, TNode* node) {
  808. using namespace NCompTriePrivate;
  809. this->insert(LowerBound(this->begin(), this->end(), s[0], TCmp()), TArc(s, node));
  810. }
  811. template <class T, class D, class S>
  812. const typename TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode*
  813. TCompactTrieBuilder<T, D, S>::TCompactTrieBuilderImpl::TNode::TArcSet::Find(
  814. TStringBuf& key, TData* value, bool& result, const TPacker& packer) const {
  815. result = false;
  816. if (!key)
  817. return nullptr;
  818. const const_iterator it = Find(key[0]);
  819. if (it != this->end()) {
  820. const char* const arcLabel = it->Label.AsCharPtr();
  821. const size_t arcLabelLen = it->Label.Length();
  822. if (key.size() >= arcLabelLen && memcmp(key.data(), arcLabel, arcLabelLen) == 0) {
  823. const TStringBuf srcKey = key;
  824. key = key.SubStr(arcLabelLen);
  825. const TNode* const node = it->Node;
  826. if (srcKey.size() == arcLabelLen) {
  827. // unpack value of it->Node, if it has value
  828. if (!node->IsFinal())
  829. return nullptr;
  830. if (value)
  831. packer.UnpackLeaf(node->GetPayload(), *value);
  832. result = true;
  833. return nullptr;
  834. }
  835. // find in subtree
  836. return node;
  837. }
  838. }
  839. return nullptr;
  840. }
  841. // Different
  842. //----------------------------------------------------------------------------------------------------------------------
  843. // Minimize the trie. The result is equivalent to the original
  844. // trie, except that it takes less space (and has marginally lower
  845. // performance, because of eventual epsilon links).
  846. // The algorithm is as follows: starting from the largest pieces, we find
  847. // nodes that have identical continuations (Daciuk's right language),
  848. // and repack the trie. Repacking is done in-place, so memory is less
  849. // of an issue; however, it may take considerable time.
  850. // IMPORTANT: never try to reminimize an already minimized trie or a trie with fast layout.
  851. // Because of non-local structure and epsilon links, it won't work
  852. // as you expect it to, and can destroy the trie in the making.
  853. template <class TPacker>
  854. size_t CompactTrieMinimize(IOutputStream& os, const char* data, size_t datalength, bool verbose /*= false*/, const TPacker& packer /*= TPacker()*/, NCompactTrie::EMinimizeMode mode) {
  855. using namespace NCompactTrie;
  856. return CompactTrieMinimizeImpl(os, data, datalength, verbose, &packer, mode);
  857. }
  858. template <class TTrieBuilder>
  859. size_t CompactTrieMinimize(IOutputStream& os, const TTrieBuilder& builder, bool verbose /*=false*/) {
  860. TBufferStream buftmp;
  861. size_t len = builder.Save(buftmp);
  862. return CompactTrieMinimize<typename TTrieBuilder::TPacker>(os, buftmp.Buffer().Data(), len, verbose);
  863. }
  864. //----------------------------------------------------------------------------------------------------------------
  865. // Lay the trie in memory in such a way that there are less cache misses when jumping from root to leaf.
  866. // The trie becomes about 2% larger, but the access became about 25% faster in our experiments.
  867. // Can be called on minimized and non-minimized tries, in the first case in requires half a trie more memory.
  868. // Calling it the second time on the same trie does nothing.
  869. //
  870. // The algorithm is based on van Emde Boas layout as described in the yandex data school lectures on external memory algoritms
  871. // by Maxim Babenko and Ivan Puzyrevsky. The difference is that when we cut the tree into levels
  872. // two nodes connected by a forward link are put into the same level (because they usually lie near each other in the original tree).
  873. // The original paper (describing the layout in Section 2.1) is:
  874. // Michael A. Bender, Erik D. Demaine, Martin Farach-Colton. Cache-Oblivious B-Trees
  875. // SIAM Journal on Computing, volume 35, number 2, 2005, pages 341-358.
  876. // Available on the web: http://erikdemaine.org/papers/CacheObliviousBTrees_SICOMP/
  877. // Or: Michael A. Bender, Erik D. Demaine, and Martin Farach-Colton. Cache-Oblivious B-Trees
  878. // Proceedings of the 41st Annual Symposium
  879. // on Foundations of Computer Science (FOCS 2000), Redondo Beach, California, November 12-14, 2000, pages 399-409.
  880. // Available on the web: http://erikdemaine.org/papers/FOCS2000b/
  881. // (there is not much difference between these papers, actually).
  882. //
  883. template <class TPacker>
  884. size_t CompactTrieMakeFastLayout(IOutputStream& os, const char* data, size_t datalength, bool verbose /*= false*/, const TPacker& packer /*= TPacker()*/) {
  885. using namespace NCompactTrie;
  886. return CompactTrieMakeFastLayoutImpl(os, data, datalength, verbose, &packer);
  887. }
  888. template <class TTrieBuilder>
  889. size_t CompactTrieMakeFastLayout(IOutputStream& os, const TTrieBuilder& builder, bool verbose /*=false*/) {
  890. TBufferStream buftmp;
  891. size_t len = builder.Save(buftmp);
  892. return CompactTrieMakeFastLayout<typename TTrieBuilder::TPacker>(os, buftmp.Buffer().Data(), len, verbose);
  893. }
  894. template <class TPacker>
  895. size_t CompactTrieMinimizeAndMakeFastLayout(IOutputStream& os, const char* data, size_t datalength, bool verbose/*=false*/, const TPacker& packer/*= TPacker()*/) {
  896. TBufferStream buftmp;
  897. size_t len = CompactTrieMinimize(buftmp, data, datalength, verbose, packer);
  898. return CompactTrieMakeFastLayout(os, buftmp.Buffer().Data(), len, verbose, packer);
  899. }
  900. template <class TTrieBuilder>
  901. size_t CompactTrieMinimizeAndMakeFastLayout(IOutputStream& os, const TTrieBuilder& builder, bool verbose /*=false*/) {
  902. TBufferStream buftmp;
  903. size_t len = CompactTrieMinimize(buftmp, builder, verbose);
  904. return CompactTrieMakeFastLayout<typename TTrieBuilder::TPacker>(os, buftmp.Buffer().Data(), len, verbose);
  905. }