8 #ifndef INCL_evo_maphash_h 9 #define INCL_evo_maphash_h 19 #pragma warning(disable:4457) 30 #define EVO_IMPL_MAPHASH_SIZEMASK(SIZE) (SIZE - 1) 31 #define EVO_IMPL_MAPHASH_THRESHOLD(SIZE) ((SIZE / 10) * 7) 207 template<
class TKey,
class TValue,
class THash=CompareHash<TKey>,
class TSize=SizeT>
214 #if defined(_MSC_VER) || defined(EVO_OLDCC) // avoid errors with older compilers and MSVC 220 typedef typename MapBaseType::IterKey IterKey;
221 typedef typename MapBaseType::IterItem IterItem;
244 MapHash(
const MapBaseType& src) :
Map<TKey,TValue,TSize>(false) {
252 MapHash(
const ThisType& src) :
Map<TKey,TValue,TSize>(false), buckets_(src.buckets_), data_(src.data_) {
256 #if defined(EVO_CPP11) 265 for (
const auto& item : init)
266 add(item.key, item.value);
272 MapHash(ThisType&& src) :
Map<TKey,TValue,TSize>(false), buckets_(std::move(src.buckets_)), data_(std::move(src.data_)) {
274 src.MapBaseType::size_ = 0;
282 buckets_ = std::move(src.buckets_);
283 data_ = std::move(src.data_);
285 src.MapBaseType::size_ = 0;
299 {
set(src);
return *
this; }
308 {
set(src);
return *
this; }
311 { buckets_.
set();
size_ = 0;
return *
this; }
313 ThisType&
set(
const MapBaseType& src) {
320 ThisType&
set(
const ThisType& src) {
321 buckets_.
set(src.buckets_);
331 { buckets_.
clear();
size_ = 0;
return *
this; }
336 {
return buckets_.
null(); }
339 {
return buckets_.
shared(); }
342 {
return buckets_.
size(); }
346 using MapBaseType::operator==;
347 using MapBaseType::operator!=;
353 {
return Iter(*
this); }
361 {
return IterM(*
this); }
365 {
return Iter(*
this); }
376 {
return (
find(key) != NULL); }
378 const Value*
find(
const Key& key)
const {
380 const Bucket* bucket = buckets_.
item( data_.hash(key) & data_.sizemask );
381 if (bucket != NULL) {
382 if (key == bucket->first.first) {
383 return &bucket->
first.second;
386 const Item* item = bucket->search(index, key, data_);
397 Bucket* bucket = buckets_.
itemM( data_.hash(key) & data_.sizemask );
398 if (bucket != NULL) {
399 if (key == bucket->first.first) {
400 return &bucket->
first.second;
403 Item* item = (Item*)bucket->search(index, key, data_);
413 Iter
iter(
const Key& key)
const {
415 IterKey iterkey( data_.hash(key) & data_.sizemask );
416 const Bucket* bucket = buckets_.
item(iterkey.a);
417 if (bucket != NULL) {
418 if (bucket->first.first == key) {
419 return Iter(*
this, iterkey, (IterItem*)&bucket->first);
421 const IterItem* item = (IterItem*)bucket->search(iterkey.b, key, data_);
424 return Iter(*
this, iterkey, item);
435 IterKey iterkey( data_.hash(key) & data_.sizemask );
436 Bucket* bucket = buckets_.
itemM(iterkey.a);
437 if (bucket != NULL) {
438 if (bucket->first.first == key) {
439 return IterM(*
this, iterkey, (IterItem*)&bucket->first);
441 IterItem* item = (IterItem*)bucket->search(iterkey.b, key, data_);
444 return IterM(*
this, iterkey, item);
452 Item&
getitem(
const Key& key,
bool* created=NULL) {
453 if (data_.threshold == 0) {
455 buckets_.
resize(SIZE_INIT);
456 data_.sizemask = EVO_IMPL_MAPHASH_SIZEMASK(SIZE_INIT);
457 data_.threshold = EVO_IMPL_MAPHASH_THRESHOLD(SIZE_INIT);
458 }
else if (
size_ >= data_.threshold) {
460 Size newsize = buckets_.
size() << 1;
461 data_.sizemask = EVO_IMPL_MAPHASH_SIZEMASK(newsize);
462 data_.threshold = EVO_IMPL_MAPHASH_THRESHOLD(newsize);
466 buckets_.
swap(oldbuckets);
470 const Bucket* bucket;
471 const Bucket** cur = (
const Bucket**)oldbuckets.
data();
472 for (
const Bucket**
end=cur+oldbuckets.
size(); cur <
end; ++cur) {
473 if ((bucket=*cur) != NULL) {
474 for (Size i=0, iend=bucket->others.size(); i <= iend; ++i) {
475 const Item* item = (i == 0 ? &bucket->first : &bucket->others[i-1]);
476 Bucket* newbucket = buckets_.
getitem(data_.hash(item->
first) & data_.sizemask, &created);
478 newbucket->
first = *item;
481 Item* newitem = (Item*)newbucket->search(index, item->
first, data_);
483 newbucket->others.insert(index, *item);
495 Bucket* bucket = buckets_.
getitem((data_.hash(key) & data_.sizemask), &created_item);
498 item = &bucket->
first;
500 }
else if (bucket->first.first == key) {
501 item = &bucket->
first;
504 item = (Item*)bucket->search(index, key, data_);
508 item = (Item*)&(bucket->others[bucket->others.insertnew(index, 1)]);
513 *created = created_item;
518 Value&
get(
const Key& key,
bool* created=NULL)
528 { buckets_.
unshare();
return *
this; }
539 const Size cursize = buckets_.
size();
540 if (size != cursize) {
542 Size newsize = SIZE_INIT;
543 while (newsize < size) newsize <<= 1;
544 while (newsize <
size_) newsize <<= 1;
546 if (newsize != cursize) {
548 data_.sizemask = EVO_IMPL_MAPHASH_SIZEMASK(newsize);
549 data_.threshold = EVO_IMPL_MAPHASH_THRESHOLD(newsize);
556 buckets_.
swap(oldbuckets);
560 const Bucket* bucket;
561 const Bucket** cur = (
const Bucket**)oldbuckets.
data();
562 for (
const Bucket**
end=cur+oldbuckets.
size(); cur <
end; ++cur) {
563 if ((bucket=*cur) != NULL) {
564 for (Size i=0, iend=bucket->others.size(); i <= iend; ++i) {
565 const Item* item = (i == 0 ? &bucket->first : &bucket->others[i-1]);
566 Bucket* newbucket = buckets_.
getitem(data_.hash(item->
first) & data_.sizemask, &created);
568 newbucket->
first = *item;
571 Item* newitem = (Item*)newbucket->search(index, item->
first, data_);
573 newbucket->others.insert(index, *item);
591 if (min > buckets_.
size())
613 Size newsize = MIN_SIZE;
614 while (newsize < size) newsize <<= 1;
615 if (newsize != buckets_.
size()) {
616 data_.sizemask = EVO_IMPL_MAPHASH_SIZEMASK(newsize);
617 data_.threshold = EVO_IMPL_MAPHASH_THRESHOLD(newsize);
619 buckets_.
swap(oldbuckets);
623 const Bucket* bucket;
624 const Bucket** cur = (
const Bucket**)oldbuckets.
data();
625 for (
const Bucket**
end=cur+oldbuckets.
size(); cur <
end; ++cur) {
626 if ((bucket=*cur) != NULL) {
627 for (Size i=0, iend=bucket->others.size(); i <= iend; ++i) {
628 const Item* item = (i == 0 ? &bucket->first : &bucket->others[i-1]);
629 Bucket* newbucket = buckets_.
getitem(data_.hash(item->
first) & data_.sizemask, &created);
631 newbucket->
first = *item;
634 Item* newitem = (Item*)newbucket->search(index, item->
first, data_);
636 newbucket->others.insert(index, *item);
648 Item&
add(
const Key& key,
const Value& value,
bool update=
true) {
650 Item& upditem =
getitem(key, &created_val);
651 if (created_val || update)
656 Item&
add(
const Item& item,
bool update=
true)
659 ThisType&
add(
const MapBaseType& map,
bool update=
true) {
670 bool remove(
const Key& key) {
672 Size bucket_index = data_.hash(key) & data_.sizemask;
673 Bucket* bucket = buckets_.
itemM(bucket_index);
674 if (bucket != NULL) {
676 if (bucket->first.first == key) {
677 if (bucket->others.size() > 0) {
679 Item* item1 = &bucket->
first;
680 Item* item2 = bucket->others.data();
681 EVO_IMPL_CONTAINER_SWAP(item1, item2, Item);
682 bucket->others.remove(0);
685 buckets_.
remove(bucket_index);
688 }
else if (bucket->search(index, key, data_) != NULL) {
690 bucket->others.remove(index);
701 {
return remove((IterM&)iter, dir); }
704 if (iter &&
this == &iter.getParent()) {
705 IterKey& iterkey = iter.getKey();
706 assert( iterkey.a < buckets_.
size() );
707 Bucket* bucket = buckets_.
itemM(iterkey.a);
708 assert( bucket != NULL );
711 bucket->others.remove(iterkey.b-1);
713 if (bucket->others.size() > 0) {
715 Item* item1 = &bucket->first;
716 Item* item2 = bucket->others.data();
717 EVO_IMPL_CONTAINER_SWAP(item1, item2, Item);
718 bucket->others.remove(0);
721 buckets_.
remove(iterkey.a);
730 if (iterkey.b > 0 && bucket != NULL) {
731 iter.setData( (IterItem*)(--iterkey.b == 0 ? &(bucket->first) : &(bucket->others[iterkey.b-1])) );
733 bucket = (Bucket*)buckets_.iterPrev(iterkey.a);
734 if (bucket != NULL) {
735 iterkey.b = bucket->others.
size();
736 iter.setData( (IterItem*)(iterkey.b == 0 ? &bucket->first : &(bucket->others[iterkey.b-1])) );
742 if (bucket != NULL && iterkey.b <= bucket->others.size()) {
743 iter.setData( (IterItem*)(iterkey.b == 0 ? &bucket->first : &(bucket->others[iterkey.b-1])) );
746 if ((bucket=(Bucket*)buckets_.iterNext(iterkey.a)) != NULL)
747 iter.setData( (IterItem*)&bucket->first );
763 #if EVO_UNIT_TEST_MODE 764 Size utCollisions()
const {
767 count += iter->others.size();
775 void iterInitMutable()
777 const IterItem* iterFirst(IterKey& key)
const {
780 return (IterItem*)&(buckets_.iterFirst(key.a)->
first);
784 const IterItem* iterNext(IterKey& key)
const {
786 const Bucket* bucket = buckets_.
item(key.a);
787 if (++key.b <= bucket->others.size())
788 return (IterItem*)&(bucket->others[key.b-1]);
790 if ((bucket=buckets_.iterNext(key.a)) != NULL)
791 return (IterItem*)&bucket->first;
795 const IterItem* iterLast(IterKey& key)
const {
797 const Bucket* bucket = buckets_.iterLast(key.a);
798 assert( bucket != NULL );
799 key.b = bucket->others.size();
800 return (IterItem*)(key.b == 0 ? &bucket->first : &(bucket->others[key.b-1]));
807 const IterItem* iterPrev(IterKey& key)
const {
810 return (IterItem*)(--key.b == 0 ? &(buckets_.
item(key.a)->
first) : &(buckets_.
item(key.a)->others[key.b-1]));
812 const Bucket* bucket = buckets_.iterPrev(key.a);
813 if (bucket != NULL) {
814 key.b = bucket->others.
size();
815 return (IterItem*)(key.b == 0 ? &bucket->first : &(bucket->others[key.b-1]));
825 const Item*
getiter(IterKey& iterkey,
const Key& key)
const {
827 iterkey.
a = (data_.hash(key) & data_.sizemask);
828 const Bucket* bucket = buckets_.
item(iterkey.a);
829 if (bucket != NULL) {
830 if (bucket->first.first == key) {
832 return &bucket->first;
834 const Item* item = bucket->search(iterkey.b, key, data_);
848 static const Size SIZE_INIT = 64;
849 static const Size MIN_SIZE = 8;
857 Bucket(
const Bucket& src) :
first(src.first), others(src.others) {
861 const Item* search(Size& index,
const Key& key,
const typename Hash::CompareBase& compare)
const {
863 Size left = 0, right = others.
size(), mid = 0;
864 const Item* items = others.
data();
865 while (left < right) {
866 mid = left + ((right-left) / 2);
867 const Item* item = items + mid;
868 cmp = compare(key, item->
first);
871 }
else if (cmp == 0) {
891 struct Data :
public THash {
895 Data() : sizemask(0), threshold(0) {
897 Data(
const Data& data) :
Hash(data), sizemask(data.sizemask), threshold(data.threshold) {
900 THash::operator=(data);
901 sizemask = data.sizemask;
902 threshold = data.threshold;
906 #if defined(EVO_CPP11) 907 Data(Data&& data) : THash(std::move((THash&&)data)), sizemask(data.sizemask), threshold(data.threshold) {
912 THash::operator=(std::move((THash&&)data));
913 sizemask = data.sizemask;
914 threshold = data.threshold;
925 #undef EVO_IMPL_MAPHASH_SIZEMASK 926 #undef EVO_IMPL_MAPHASH_THRESHOLD 930 #if defined(INCL_evo_string_h) || defined(DOXYGEN) 941 #if defined(_MSC_VER) bool shared() const
Get whether shared.
Definition: maphash.h:338
Iter cbegin() const
Get iterator at first item (const).
Definition: maphash.h:352
ThisType & reserve(Size size)
Reserve space for new items.
Definition: maphash.h:597
Item & add(const Item &item, bool update=true)
Add or update using given item.
Definition: maphash.h:656
Pair< Key, Value > Item
Item type (key/value pair)
Definition: map.h:137
ThisType & operator=(const ThisType &src)
Assignment operator.
Definition: maphash.h:307
Item getitem(const Key &key, bool *created=NULL)
Get item for key, creating if needed (mutable).
Definition: ptrlist.h:717
Size size() const
Get size.
Definition: array.h:453
IteratorBi< ThisType >::Const Iter
Iterator (const) - IteratorBi.
Definition: maphash.h:234
const A & a() const
Get first value (const).
Definition: pair.h:102
Map< TKey, TValue, TSize > MapBaseType
Map base type
Definition: map.h:133
Size capacity() const
Get map capacity.
Definition: maphash.h:341
Size size_
Map size (number of items, automatically updated by concrete set members)
Definition: map.h:180
Iter iter(const Key &key) const
Find (lookup) iterator for given key (const).
Definition: maphash.h:413
Iter begin() const
Get iterator at first item (const).
Definition: maphash.h:364
const Value * find(const Key &key) const
Find (lookup) value for given key (const).
Definition: maphash.h:378
T first(T val1, T val2)
Definition: alg.h:85
Random access iterator.
Definition: iter.h:904
ThisType & add(const MapBaseType &map, bool update=true)
Definition: maphash.h:659
MapHash(const ThisType &src)
Copy constructor.
Definition: maphash.h:252
Item & getitem(const Key &key, bool *created=NULL)
Get map item for key (mutable).
Definition: maphash.h:452
#define EVO_ONCPP11(EXPR)
Compile EXPR only if C++11 support is detected, otherwise this is a no-op.
Definition: sys.h:259
Evo implementation detail: Hashing support.
ThisType & operator=(ThisType &&src)
Move assignment operator (C++11).
Definition: maphash.h:281
ThisType & unshare()
Make sure data is not shared by allocating new buffer if needed (modifier).
Definition: ptrlist.h:790
bool contains(const Key &key) const
Get whether map contains the given key.
Definition: maphash.h:375
ThisType & capacity(Size size)
Set hash map size (capacity).
Definition: maphash.h:538
Item & add(const Key &key, const Value &value, bool update=true)
Add or update using given key and value.
Definition: maphash.h:648
Iter cend() const
Get iterator at end (const).
Definition: maphash.h:356
Value & operator[](const Key &key)
Get item value for key (mutable).
Definition: maphash.h:524
Basic integer type.
Definition: type.h:980
const B & b() const
Get second value (const).
Definition: pair.h:126
TKey Key
Key type.
Definition: map.h:135
MapHash(const MapBaseType &src)
Copy constructor.
Definition: maphash.h:244
IterM iterM(const Key &key)
Find (lookup) iterator for given key (mutable).
Definition: maphash.h:433
ThisType & setempty()
Set as empty but not null.
Definition: maphash.h:327
const T * data() const
Get data pointer (const).
Definition: array.h:469
MapHash< String, String > StrHash
MapHash using String keys and values.
Definition: maphash.h:935
bool null() const
Get whether null.
Definition: ptrlist.h:400
ThisType & resize(Size newsize)
Resize while preserving existing data (modifier).
Definition: ptrlist.h:814
ThisType & unshare()
Make data unique by allocating new buffer, if needed (modifier).
Definition: maphash.h:527
Bidirectional iterator.
Definition: iter.h:611
TA first
First value (same as a() and key())
Definition: pair.h:42
void swap(ThisType &list)
Swap with another list.
Definition: ptrlist.h:1085
const Item * getiter(IterKey &iterkey, const Key &key) const
Used by base class to get data to initialize iterator.
Definition: maphash.h:825
ThisType & setempty()
Set as empty but not null.
Definition: ptrlist.h:385
static const EndT END
Special integer value for indicating end of items or no item.
Definition: type.h:1846
TValue Value
Value type.
Definition: map.h:136
IterM begin()
Get iterator at first item (mutable).
Definition: maphash.h:360
IteratorDir
Iterator direction value.
Definition: iter.h:27
MapHash< TKey, TValue, THash, TSize > ThisType
This type.
Definition: maphash.h:231
bool shared() const
Get whether shared.
Definition: ptrlist.h:428
Reverse iterator direction.
Definition: iter.h:30
MapHash()
Constructor.
Definition: maphash.h:238
Evo C++ Library namespace.
Definition: alg.h:11
No iterator direction.
Definition: iter.h:28
IteratorBi< ThisType > IterM
Iterator (mutable) - IteratorBi.
Definition: maphash.h:235
TSize Size
Size type for size values (must be unsigned integer) – default: SizeT.
Definition: map.h:134
const Item first() const
Get first non-null item (const).
Definition: ptrlist.h:474
Size size() const
Get map size (number of items).
Definition: map.h:272
Item itemM(Key index)
Get item at position (mutable).
Definition: ptrlist.h:780
IterM end()
Get iterator at end.
Definition: maphash.h:368
End iterator position.
Definition: iter.h:23
ThisType & operator=(const MapBaseType &src)
Assignment operator.
Definition: maphash.h:298
MapHash(ThisType &&src)
Move constructor (C++11).
Definition: maphash.h:272
const ThisType & asconst() const
Explicitly use a const reference to this.
Definition: maphash.h:291
Value * findM(const Key &key)
Find (lookup) value for given key (mutable).
Definition: maphash.h:395
ThisType & clear()
Clear by removing all items.
Definition: ptrlist.h:313
bool null() const
Get whether map is null.
Definition: maphash.h:335
ThisType & remove(Key key)
Remove item and set as null (modifier).
Definition: ptrlist.h:987
THash Hash
Hashing type – default: CompareHash.
Definition: maphash.h:232
const Item item(Key index) const
Get item at position (const).
Definition: ptrlist.h:461
void resize(Size size)
Set hash map size (capacity) directly.
Definition: maphash.h:612
Stores a key/value pair of independent objects or values.
Definition: pair.h:32
Size size() const
Get list size.
Definition: ptrlist.h:414
ThisType & set()
Set as null and empty.
Definition: ptrlist.h:339
Iter end() const
Get iterator at end (const).
Definition: maphash.h:372
const Item * data() const
Get data pointer for direct access (const).
Definition: ptrlist.h:437
ThisType & clear()
Clear by removing all items.
Definition: maphash.h:330
ThisType & capacitymin(Size min)
Set map capacity to at least given minimum.
Definition: maphash.h:590
Associative container holding key/value pairs for fast lookup.
Definition: map.h:129
T & min(T &a, T &b)
Returns lowest of given values.
Definition: alg.h:26
MapHash(const std::initializer_list< InitPair > &init)
< Used with initializer_list constructor (C++11)
Definition: maphash.h:262
Map implemented as a hash table.
Definition: maphash.h:208
TB second
Second value (same as b() and value())
Definition: pair.h:43
Initializer key/value pair, used with initializer (C++11).
Definition: map.h:162