#pragma once #include #include #include #include #include // less<> and equal_to<> for const char* #include #include template , class EqualTo = TEqualTo, class Alloc = std::allocator> class string_hash; template , class EqualTo = TEqualTo> class segmented_string_hash; template inline std::pair pool_insert(Map* m, const char* key, const typename Map::mapped_type& data, TBuffer& pool) { std::pair ins = m->insert(typename Map::value_type(key, data)); if (ins.second) { // new? size_t buflen = strlen(key) + 1; // strlen??? const char* old_pool = pool.Begin(); pool.Append(key, buflen); if (pool.Begin() != old_pool) // repoint? for (typename Map::iterator it = m->begin(); it != m->end(); ++it) if ((*it).first != key) const_cast((*it).first) += (pool.Begin() - old_pool); const_cast((*ins.first).first) = pool.End() - buflen; } return ins; } #define HASH_SIZE_DEFAULT 100 #define AVERAGEWORD_BUF 10 template class string_hash: public THashMap { protected: TBuffer pool; public: using yh = THashMap; using iterator = typename yh::iterator; using const_iterator = typename yh::const_iterator; using mapped_type = typename yh::mapped_type; using size_type = typename yh::size_type; using pool_size_type = typename yh::size_type; string_hash() { pool.Reserve(HASH_SIZE_DEFAULT * AVERAGEWORD_BUF); // reserve here } string_hash(size_type hash_size, pool_size_type pool_size) : THashMap(hash_size) { pool.Reserve(pool_size); // reserve here } std::pair insert_copy(const char* key, const mapped_type& data) { return ::pool_insert(this, key, data, pool); } void clear_hash() { yh::clear(); pool.Clear(); } pool_size_type pool_size() const { return pool.Size(); } string_hash(const string_hash& sh) : THashMap() { for (const_iterator i = sh.begin(); i != sh.end(); ++i) insert_copy((*i).first, (*i).second); } /* May be faster? string_hash(const string_hash& sh) : THashMap(sh) { pool = sh.pool; size_t delta = pool.begin() - sh.pool.begin(); for (iterator i = begin(); i != end(); ++i) (const char*&)(*i).first += delta; } */ string_hash& operator=(const string_hash& sh) { if (&sh != this) { clear_hash(); for (const_iterator i = sh.begin(); i != sh.end(); ++i) insert_copy((*i).first, (*i).second); } return *this; } mapped_type& operator[](const char* key) { iterator I = yh::find(key); if (I == yh::end()) I = insert_copy(key, mapped_type()).first; return (*I).second; } }; template class THashWithSegmentedPoolForKeys: protected THashMap, TNonCopyable { protected: segmented_pool pool; public: using yh = THashMap; using iterator = typename yh::iterator; using const_iterator = typename yh::const_iterator; using mapped_type = typename yh::mapped_type; using size_type = typename yh::size_type; using key_type = typename yh::key_type; using value_type = typename yh::value_type; THashWithSegmentedPoolForKeys(size_type hash_size = HASH_SIZE_DEFAULT, size_t segsize = HASH_SIZE_DEFAULT * AVERAGEWORD_BUF, bool afs = false) : yh(hash_size) , pool(segsize) { if (afs) pool.alloc_first_seg(); } std::pair insert_copy(const C* key, size_t keylen, const mapped_type& data) { std::pair ins = this->insert(value_type(key, data)); if (ins.second) // new? (const C*&)(*ins.first).first = pool.append(key, keylen); return ins; } void clear_hash() { yh::clear(); pool.restart(); } size_t pool_size() const { return pool.size(); } size_t size() const { return yh::size(); } bool empty() const { return yh::empty(); } iterator begin() { return yh::begin(); } iterator end() { return yh::end(); } const_iterator begin() const { return yh::begin(); } const_iterator end() const { return yh::end(); } iterator find(const key_type& key) { return yh::find(key); } const_iterator find(const key_type& key) const { return yh::find(key); } const yh& get_THashMap() const { return static_cast(*this); } }; template class segmented_string_hash: public THashWithSegmentedPoolForKeys { public: using Base = THashWithSegmentedPoolForKeys; using iterator = typename Base::iterator; using const_iterator = typename Base::const_iterator; using mapped_type = typename Base::mapped_type; using size_type = typename Base::size_type; using key_type = typename Base::key_type; using value_type = typename Base::value_type; public: segmented_string_hash(size_type hash_size = HASH_SIZE_DEFAULT, size_t segsize = HASH_SIZE_DEFAULT * AVERAGEWORD_BUF, bool afs = false) : Base(hash_size, segsize, afs) { } std::pair insert_copy(const char* key, const mapped_type& data) { return Base::insert_copy(key, strlen(key) + 1, data); } mapped_type& operator[](const char* key) { iterator I = Base::find(key); if (I == Base::end()) I = insert_copy(key, mapped_type()).first; return (*I).second; } };