@@ -242,7 +242,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::~FlatMap() {
242242 clear ();
243243 get_allocator ().Free (_buckets);
244244 _buckets = NULL ;
245- free (_thumbnail);
245+ bit_array_free (_thumbnail);
246246 _thumbnail = NULL ;
247247 _nbucket = 0 ;
248248 _load_factor = 0 ;
@@ -272,35 +272,32 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::operator=(const FlatMap<_K, _T, _H, _E, _S,
272272 if (!rhs.initialized ()) {
273273 return *this ;
274274 }
275- bool need_copy = !rhs.empty ();
276275 _load_factor = rhs._load_factor ;
277276 if (_buckets == NULL || is_too_crowded (rhs._size )) {
278- get_allocator ().Free (_buckets);
279- _nbucket = rhs._nbucket ;
280- // note: need an extra bucket to let iterator know where buckets end
281- _buckets = (Bucket*)get_allocator ().Alloc (sizeof (Bucket) * (_nbucket + 1 /* note*/ ));
282- if (NULL == _buckets) {
283- LOG (ERROR ) << " Fail to new _buckets" ;
277+ NewBucketsInfo info = new_buckets_and_thumbnail (_size, rhs._nbucket );
278+ if (0 == info.nbucket ) {
279+ LOG (ERROR ) << " Invalid nbucket=0" ;
284280 return *this ;
285281 }
286- // If no need to copy, set buckets invalid.
287- if (!need_copy) {
288- for (size_t i = 0 ; i < _nbucket; ++i) {
289- _buckets[i].set_invalid ();
290- }
291- _buckets[_nbucket].next = NULL ;
282+ if (NULL == info.buckets ) {
283+ LOG (ERROR ) << " Fail to new buckets" ;
284+ return *this ;
292285 }
286+ if (_S && NULL == info.thumbnail ) {
287+ LOG (ERROR ) << " Fail to new thumbnail" ;
288+ return *this ;
289+ }
290+
291+ _nbucket = info.nbucket ;
292+ get_allocator ().Free (_buckets);
293+ _buckets = info.buckets ;
293294 if (_S) {
294- free (_thumbnail);
295- _thumbnail = bit_array_malloc (_nbucket);
296- if (NULL == _thumbnail) {
297- LOG (ERROR ) << " Fail to new _thumbnail" ;
298- return *this ;
299- }
300- bit_array_clear (_thumbnail, _nbucket);
295+ bit_array_free (_thumbnail);
296+ _thumbnail = info.thumbnail ;
301297 }
302298 }
303- if (!need_copy) {
299+ if (rhs.empty ()) {
300+ // No need to copy, returns directly.
304301 return *this ;
305302 }
306303 if (_nbucket == rhs._nbucket ) {
@@ -327,7 +324,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::operator=(const FlatMap<_K, _T, _H, _E, _S,
327324 _size = rhs._size ;
328325 } else {
329326 for (const_iterator it = rhs.begin (); it != rhs.end (); ++it) {
330- operator [](Element::first_ref_from_value (*it)) =
327+ operator [](Element::first_ref_from_value (*it)) =
331328 Element::second_ref_from_value (*it);
332329 }
333330 }
@@ -341,33 +338,33 @@ int FlatMap<_K, _T, _H, _E, _S, _A, _M>::init(size_t nbucket, u_int load_factor)
341338 return -1 ;
342339 }
343340 if (nbucket == 0 ) {
344- LOG (WARNING ) << " Fail to init FlatMap, nbucket=" << nbucket;
341+ LOG (WARNING ) << " Fail to init FlatMap, nbucket=" << nbucket;
345342 return -1 ;
346343 }
347344 if (load_factor < 10 || load_factor > 100 ) {
348345 LOG (ERROR ) << " Invalid load_factor=" << load_factor;
349346 return -1 ;
350347 }
351348 _size = 0 ;
352- _nbucket = flatmap_round (nbucket);
353349 _load_factor = load_factor;
354-
355- _buckets = (Bucket*) get_allocator (). Alloc ( sizeof (Bucket) * (_nbucket + 1 ) );
356- if (NULL == _buckets ) {
357- LOG (ERROR ) << " Fail to new _buckets " ;
350+
351+ NewBucketsInfo info = new_buckets_and_thumbnail (_size, nbucket );
352+ if (0 == info. nbucket ) {
353+ LOG (ERROR ) << " Invalid nbucket=0 " ;
358354 return -1 ;
359355 }
360- for (size_t i = 0 ; i < _nbucket; ++i) {
361- _buckets[i].set_invalid ();
356+ if (NULL == info.buckets ) {
357+ LOG (ERROR ) << " Fail to new buckets" ;
358+ return -1 ;
362359 }
363- _buckets[_nbucket].next = NULL ;
364-
360+ if (_S && NULL == info.thumbnail ) {
361+ LOG (ERROR ) << " Fail to new thumbnail" ;
362+ return -1 ;
363+ }
364+ _nbucket = info.nbucket ;
365+ _buckets = info.buckets ;
365366 if (_S) {
366- _thumbnail = bit_array_malloc (_nbucket);
367- if (NULL == _thumbnail) {
368- LOG (ERROR ) << " Fail to new _thumbnail" ;
369- return -1 ;
370- }
367+ _thumbnail = info.thumbnail ;
371368 bit_array_clear (_thumbnail, _nbucket);
372369 }
373370 return 0 ;
@@ -625,7 +622,7 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::operator[](const key_type& key) {
625622 return first_node.element ().second_ref ();
626623 }
627624 Bucket *p = &first_node;
628- while (1 ) {
625+ while (true ) {
629626 if (_eql (p->element ().first_ref (), key)) {
630627 return p->element ().second_ref ();
631628 }
@@ -659,6 +656,24 @@ FlatMap<_K, _T, _H, _E, _S, _A, _M>::operator[](const key_type& key) {
659656 new (&first_node) Bucket (key);
660657 return first_node.element ().second_ref ();
661658 }
659+ if (is_too_crowded (_size)) {
660+ Bucket *p = &first_node;
661+ bool need_scale = false ;
662+ while (NULL != p) {
663+ // Increase the capacity of bucket when
664+ // hash collision occur and map is crowded.
665+ if (!_eql (p->element ().first_ref (), key)) {
666+ need_scale = true ;
667+ break ;
668+ }
669+ p = p->next ;
670+ }
671+ if (need_scale && resize (_nbucket + 1 )) {
672+ return operator [](key);
673+ }
674+ // fail to resize is OK
675+ }
676+ ++_size;
662677 Bucket* newp = new (_pool.get ()) Bucket (key);
663678 newp->next = first_node.next ;
664679 first_node.next = newp;
@@ -720,15 +735,15 @@ bool FlatMap<_K, _T, _H, _E, _S, _A, _M>::resize(size_t nbucket2) {
720735 return false ;
721736 }
722737
723- // NOTE: following functors must be kept after resizing otherwise the
738+ // NOTE: following functors must be kept after resizing otherwise the
724739 // internal state is lost.
725740 FlatMap new_map (_hashfn, _eql, get_allocator ());
726741 if (new_map.init (nbucket2, _load_factor) != 0 ) {
727742 LOG (ERROR ) << " Fail to init new_map, nbucket=" << nbucket2;
728743 return false ;
729744 }
730745 for (iterator it = begin (); it != end (); ++it) {
731- new_map[Element::first_ref_from_value (*it)] =
746+ new_map[Element::first_ref_from_value (*it)] =
732747 Element::second_movable_ref_from_value (*it);
733748 }
734749 new_map.swap (*this );
@@ -751,6 +766,38 @@ BucketInfo FlatMap<_K, _T, _H, _E, _S, _A, _M>::bucket_info() const {
751766 return info;
752767}
753768
769+ template <typename _K, typename _T, typename _H, typename _E, bool _S, typename _A, bool _M>
770+ typename FlatMap<_K, _T, _H, _E, _S, _A, _M>::NewBucketsInfo
771+ FlatMap<_K, _T, _H, _E, _S, _A, _M>::new_buckets_and_thumbnail(size_t size,
772+ size_t new_nbucket) {
773+ do {
774+ new_nbucket = flatmap_round (new_nbucket);
775+ } while (is_too_crowded (size, new_nbucket, _load_factor));
776+ // Note: need an extra bucket to let iterator know where buckets end.
777+ auto buckets = (Bucket*)get_allocator ().Alloc (sizeof (Bucket) * (
778+ new_nbucket + 1 /* note*/ ));
779+ auto guard = MakeScopeGuard ([buckets, this ]() {
780+ get_allocator ().Free (buckets);
781+ });
782+ if (NULL == buckets) {
783+ LOG (FATAL ) << " Fail to new Buckets" ;
784+ return {};
785+ }
786+
787+ uint64_t * thumbnail = NULL ;
788+ if (_S) {
789+ thumbnail = bit_array_malloc (new_nbucket);
790+ if (NULL == thumbnail) {
791+ LOG (FATAL ) << " Fail to new thumbnail" ;
792+ return {};
793+ }
794+ }
795+
796+ guard.dismiss ();
797+ init_buckets_and_thumbnail (buckets, thumbnail, new_nbucket);
798+ return { buckets, thumbnail, new_nbucket };
799+ }
800+
754801inline std::ostream& operator <<(std::ostream& os, const BucketInfo& info) {
755802 return os << " {maxb=" << info.longest_length
756803 << " avgb=" << info.average_length << ' }' ;
0 commit comments