#pragma once #include <library/cpp/on_disk/chunks/chunked_helpers.h> #include "comptrie.h" class TTrieSet { private: TCompactTrie<char> Trie; public: TTrieSet(const TBlob& blob) : Trie(blob) { } bool Has(const char* key) const { return Trie.Find(key, strlen(key)); } bool FindLongestPrefix(const char* key, size_t keylen, size_t* prefixLen) { return Trie.FindLongestPrefix(key, keylen, prefixLen); } }; template <bool sorted = false> class TTrieSetWriter { private: TCompactTrieBuilder<char> Builder; public: TTrieSetWriter(bool isSorted = sorted) : Builder(isSorted ? CTBF_PREFIX_GROUPED : CTBF_NONE) { } void Add(const char* key, size_t keylen) { Builder.Add(key, keylen, 0); assert(Has(((TString)key).substr(0, keylen).data())); } void Add(const char* key) { Add(key, strlen(key)); } bool Has(const char* key) const { ui64 dummy; return Builder.Find(key, strlen(key), &dummy); } void Save(IOutputStream& out) const { Builder.Save(out); } void Clear() { Builder.Clear(); } }; template <bool isWriter, bool sorted = false> struct TTrieSetG; template <bool sorted> struct TTrieSetG<false, sorted> { typedef TTrieSet T; }; template <bool sorted> struct TTrieSetG<true, sorted> { typedef TTrieSetWriter<sorted> T; }; template <typename T> class TTrieMap { private: TCompactTrie<char> Trie; static_assert(sizeof(T) <= sizeof(ui64), "expect sizeof(T) <= sizeof(ui64)"); public: TTrieMap(const TBlob& blob) : Trie(blob) { } bool Get(const char* key, T* value) const { ui64 trieValue; if (Trie.Find(key, strlen(key), &trieValue)) { *value = ReadUnaligned<T>(&trieValue); return true; } else { return false; } } T Get(const char* key, T def = T()) const { ui64 trieValue; if (Trie.Find(key, strlen(key), &trieValue)) { return ReadUnaligned<T>(&trieValue); } else { return def; } } const TCompactTrie<char>& GetTrie() const { return Trie; } }; template <typename T, bool sorted = false> class TTrieMapWriter { private: typedef TCompactTrieBuilder<char> TBuilder; TBuilder Builder; static_assert(sizeof(T) <= sizeof(ui64), "expect sizeof(T) <= sizeof(ui64)"); #ifndef NDEBUG bool IsSorted; #endif public: TTrieMapWriter(bool isSorted = sorted) : Builder(isSorted ? CTBF_PREFIX_GROUPED : CTBF_NONE) #ifndef NDEBUG , IsSorted(isSorted) #endif { } void Add(const char* key, const T& value) { ui64 intValue = 0; memcpy(&intValue, &value, sizeof(T)); Builder.Add(key, strlen(key), intValue); #ifndef NDEBUG /* if (!IsSorted) { T test; assert(Get(key, &test) && value == test); } */ #endif } void Add(const TString& s, const T& value) { ui64 intValue = 0; memcpy(&intValue, &value, sizeof(T)); Builder.Add(s.data(), s.size(), intValue); } bool Get(const char* key, T* value) const { ui64 trieValue; if (Builder.Find(key, strlen(key), &trieValue)) { *value = ReadUnaligned<T>(&trieValue); return true; } else { return false; } } T Get(const char* key, T def = (T)0) const { ui64 trieValue; if (Builder.Find(key, strlen(key), &trieValue)) { return ReadUnaligned<T>(&trieValue); } else { return def; } } void Save(IOutputStream& out, bool minimize = false) const { if (minimize) { CompactTrieMinimize<TBuilder>(out, Builder, false); } else { Builder.Save(out); } } void Clear() { Builder.Clear(); } }; template <typename T> class TTrieSortedMapWriter { private: typedef std::pair<TString, T> TValue; typedef TVector<TValue> TValues; TValues Values; public: TTrieSortedMapWriter() = default; void Add(const char* key, const T& value) { Values.push_back(TValue(key, value)); } void Save(IOutputStream& out) { Sort(Values.begin(), Values.end()); TTrieMapWriter<T, true> writer; for (typename TValues::const_iterator toValue = Values.begin(); toValue != Values.end(); ++toValue) writer.Add(toValue->first.data(), toValue->second); writer.Save(out); } void Clear() { Values.clear(); } }; template <typename X, bool isWriter, bool sorted = false> struct TTrieMapG; template <typename X, bool sorted> struct TTrieMapG<X, false, sorted> { typedef TTrieMap<X> T; }; template <typename X, bool sorted> struct TTrieMapG<X, true, sorted> { typedef TTrieMapWriter<X, sorted> T; };