• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2007-2010 Baptiste Lepilleur
2// Distributed under MIT license, or public domain if desired and
3// recognized in your jurisdiction.
4// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5
6// included by json_value.cpp
7
8namespace Json {
9
10// //////////////////////////////////////////////////////////////////
11// //////////////////////////////////////////////////////////////////
12// //////////////////////////////////////////////////////////////////
13// class ValueInternalMap
14// //////////////////////////////////////////////////////////////////
15// //////////////////////////////////////////////////////////////////
16// //////////////////////////////////////////////////////////////////
17
18/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
19   * This optimization is used by the fast allocator.
20   */
21ValueInternalLink::ValueInternalLink()
22   : previous_( 0 )
23   , next_( 0 )
24{
25}
26
27ValueInternalLink::~ValueInternalLink()
28{
29   for ( int index =0; index < itemPerLink; ++index )
30   {
31      if ( !items_[index].isItemAvailable() )
32      {
33         if ( !items_[index].isMemberNameStatic() )
34            free( keys_[index] );
35      }
36      else
37         break;
38   }
39}
40
41
42
43ValueMapAllocator::~ValueMapAllocator()
44{
45}
46
47#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
48class DefaultValueMapAllocator : public ValueMapAllocator
49{
50public: // overridden from ValueMapAllocator
51   virtual ValueInternalMap *newMap()
52   {
53      return new ValueInternalMap();
54   }
55
56   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
57   {
58      return new ValueInternalMap( other );
59   }
60
61   virtual void destructMap( ValueInternalMap *map )
62   {
63      delete map;
64   }
65
66   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
67   {
68      return new ValueInternalLink[size];
69   }
70
71   virtual void releaseMapBuckets( ValueInternalLink *links )
72   {
73      delete [] links;
74   }
75
76   virtual ValueInternalLink *allocateMapLink()
77   {
78      return new ValueInternalLink();
79   }
80
81   virtual void releaseMapLink( ValueInternalLink *link )
82   {
83      delete link;
84   }
85};
86#else
87/// @todo make this thread-safe (lock when accessign batch allocator)
88class DefaultValueMapAllocator : public ValueMapAllocator
89{
90public: // overridden from ValueMapAllocator
91   virtual ValueInternalMap *newMap()
92   {
93      ValueInternalMap *map = mapsAllocator_.allocate();
94      new (map) ValueInternalMap(); // placement new
95      return map;
96   }
97
98   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
99   {
100      ValueInternalMap *map = mapsAllocator_.allocate();
101      new (map) ValueInternalMap( other ); // placement new
102      return map;
103   }
104
105   virtual void destructMap( ValueInternalMap *map )
106   {
107      if ( map )
108      {
109         map->~ValueInternalMap();
110         mapsAllocator_.release( map );
111      }
112   }
113
114   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
115   {
116      return new ValueInternalLink[size];
117   }
118
119   virtual void releaseMapBuckets( ValueInternalLink *links )
120   {
121      delete [] links;
122   }
123
124   virtual ValueInternalLink *allocateMapLink()
125   {
126      ValueInternalLink *link = linksAllocator_.allocate();
127      memset( link, 0, sizeof(ValueInternalLink) );
128      return link;
129   }
130
131   virtual void releaseMapLink( ValueInternalLink *link )
132   {
133      link->~ValueInternalLink();
134      linksAllocator_.release( link );
135   }
136private:
137   BatchAllocator<ValueInternalMap,1> mapsAllocator_;
138   BatchAllocator<ValueInternalLink,1> linksAllocator_;
139};
140#endif
141
142static ValueMapAllocator *&mapAllocator()
143{
144   static DefaultValueMapAllocator defaultAllocator;
145   static ValueMapAllocator *mapAllocator = &defaultAllocator;
146   return mapAllocator;
147}
148
149static struct DummyMapAllocatorInitializer {
150   DummyMapAllocatorInitializer()
151   {
152      mapAllocator();      // ensure mapAllocator() statics are initialized before main().
153   }
154} dummyMapAllocatorInitializer;
155
156
157
158// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
159
160/*
161use linked list hash map.
162buckets array is a container.
163linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
164value have extra state: valid, available, deleted
165*/
166
167
168ValueInternalMap::ValueInternalMap()
169   : buckets_( 0 )
170   , tailLink_( 0 )
171   , bucketsSize_( 0 )
172   , itemCount_( 0 )
173{
174}
175
176
177ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
178   : buckets_( 0 )
179   , tailLink_( 0 )
180   , bucketsSize_( 0 )
181   , itemCount_( 0 )
182{
183   reserve( other.itemCount_ );
184   IteratorState it;
185   IteratorState itEnd;
186   other.makeBeginIterator( it );
187   other.makeEndIterator( itEnd );
188   for ( ; !equals(it,itEnd); increment(it) )
189   {
190      bool isStatic;
191      const char *memberName = key( it, isStatic );
192      const Value &aValue = value( it );
193      resolveReference(memberName, isStatic) = aValue;
194   }
195}
196
197
198ValueInternalMap &
199ValueInternalMap::operator =( const ValueInternalMap &other )
200{
201   ValueInternalMap dummy( other );
202   swap( dummy );
203   return *this;
204}
205
206
207ValueInternalMap::~ValueInternalMap()
208{
209   if ( buckets_ )
210   {
211      for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
212      {
213         ValueInternalLink *link = buckets_[bucketIndex].next_;
214         while ( link )
215         {
216            ValueInternalLink *linkToRelease = link;
217            link = link->next_;
218            mapAllocator()->releaseMapLink( linkToRelease );
219         }
220      }
221      mapAllocator()->releaseMapBuckets( buckets_ );
222   }
223}
224
225
226void
227ValueInternalMap::swap( ValueInternalMap &other )
228{
229   ValueInternalLink *tempBuckets = buckets_;
230   buckets_ = other.buckets_;
231   other.buckets_ = tempBuckets;
232   ValueInternalLink *tempTailLink = tailLink_;
233   tailLink_ = other.tailLink_;
234   other.tailLink_ = tempTailLink;
235   BucketIndex tempBucketsSize = bucketsSize_;
236   bucketsSize_ = other.bucketsSize_;
237   other.bucketsSize_ = tempBucketsSize;
238   BucketIndex tempItemCount = itemCount_;
239   itemCount_ = other.itemCount_;
240   other.itemCount_ = tempItemCount;
241}
242
243
244void
245ValueInternalMap::clear()
246{
247   ValueInternalMap dummy;
248   swap( dummy );
249}
250
251
252ValueInternalMap::BucketIndex
253ValueInternalMap::size() const
254{
255   return itemCount_;
256}
257
258bool
259ValueInternalMap::reserveDelta( BucketIndex growth )
260{
261   return reserve( itemCount_ + growth );
262}
263
264bool
265ValueInternalMap::reserve( BucketIndex newItemCount )
266{
267   if ( !buckets_  &&  newItemCount > 0 )
268   {
269      buckets_ = mapAllocator()->allocateMapBuckets( 1 );
270      bucketsSize_ = 1;
271      tailLink_ = &buckets_[0];
272   }
273//   BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
274   return true;
275}
276
277
278const Value *
279ValueInternalMap::find( const char *key ) const
280{
281   if ( !bucketsSize_ )
282      return 0;
283   HashKey hashedKey = hash( key );
284   BucketIndex bucketIndex = hashedKey % bucketsSize_;
285   for ( const ValueInternalLink *current = &buckets_[bucketIndex];
286         current != 0;
287         current = current->next_ )
288   {
289      for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
290      {
291         if ( current->items_[index].isItemAvailable() )
292            return 0;
293         if ( strcmp( key, current->keys_[index] ) == 0 )
294            return &current->items_[index];
295      }
296   }
297   return 0;
298}
299
300
301Value *
302ValueInternalMap::find( const char *key )
303{
304   const ValueInternalMap *constThis = this;
305   return const_cast<Value *>( constThis->find( key ) );
306}
307
308
309Value &
310ValueInternalMap::resolveReference( const char *key,
311                                    bool isStatic )
312{
313   HashKey hashedKey = hash( key );
314   if ( bucketsSize_ )
315   {
316      BucketIndex bucketIndex = hashedKey % bucketsSize_;
317      ValueInternalLink **previous = 0;
318      BucketIndex index;
319      for ( ValueInternalLink *current = &buckets_[bucketIndex];
320            current != 0;
321            previous = &current->next_, current = current->next_ )
322      {
323         for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
324         {
325            if ( current->items_[index].isItemAvailable() )
326               return setNewItem( key, isStatic, current, index );
327            if ( strcmp( key, current->keys_[index] ) == 0 )
328               return current->items_[index];
329         }
330      }
331   }
332
333   reserveDelta( 1 );
334   return unsafeAdd( key, isStatic, hashedKey );
335}
336
337
338void
339ValueInternalMap::remove( const char *key )
340{
341   HashKey hashedKey = hash( key );
342   if ( !bucketsSize_ )
343      return;
344   BucketIndex bucketIndex = hashedKey % bucketsSize_;
345   for ( ValueInternalLink *link = &buckets_[bucketIndex];
346         link != 0;
347         link = link->next_ )
348   {
349      BucketIndex index;
350      for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
351      {
352         if ( link->items_[index].isItemAvailable() )
353            return;
354         if ( strcmp( key, link->keys_[index] ) == 0 )
355         {
356            doActualRemove( link, index, bucketIndex );
357            return;
358         }
359      }
360   }
361}
362
363void
364ValueInternalMap::doActualRemove( ValueInternalLink *link,
365                                  BucketIndex index,
366                                  BucketIndex bucketIndex )
367{
368   // find last item of the bucket and swap it with the 'removed' one.
369   // set removed items flags to 'available'.
370   // if last page only contains 'available' items, then desallocate it (it's empty)
371   ValueInternalLink *&lastLink = getLastLinkInBucket( index );
372   BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
373   for ( ;
374         lastItemIndex < ValueInternalLink::itemPerLink;
375         ++lastItemIndex ) // may be optimized with dicotomic search
376   {
377      if ( lastLink->items_[lastItemIndex].isItemAvailable() )
378         break;
379   }
380
381   BucketIndex lastUsedIndex = lastItemIndex - 1;
382   Value *valueToDelete = &link->items_[index];
383   Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
384   if ( valueToDelete != valueToPreserve )
385      valueToDelete->swap( *valueToPreserve );
386   if ( lastUsedIndex == 0 )  // page is now empty
387   {  // remove it from bucket linked list and delete it.
388      ValueInternalLink *linkPreviousToLast = lastLink->previous_;
389      if ( linkPreviousToLast != 0 )   // can not deleted bucket link.
390      {
391         mapAllocator()->releaseMapLink( lastLink );
392         linkPreviousToLast->next_ = 0;
393         lastLink = linkPreviousToLast;
394      }
395   }
396   else
397   {
398      Value dummy;
399      valueToPreserve->swap( dummy ); // restore deleted to default Value.
400      valueToPreserve->setItemUsed( false );
401   }
402   --itemCount_;
403}
404
405
406ValueInternalLink *&
407ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
408{
409   if ( bucketIndex == bucketsSize_ - 1 )
410      return tailLink_;
411   ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
412   if ( !previous )
413      previous = &buckets_[bucketIndex];
414   return previous;
415}
416
417
418Value &
419ValueInternalMap::setNewItem( const char *key,
420                              bool isStatic,
421                              ValueInternalLink *link,
422                              BucketIndex index )
423{
424   char *duplicatedKey = makeMemberName( key );
425   ++itemCount_;
426   link->keys_[index] = duplicatedKey;
427   link->items_[index].setItemUsed();
428   link->items_[index].setMemberNameIsStatic( isStatic );
429   return link->items_[index]; // items already default constructed.
430}
431
432
433Value &
434ValueInternalMap::unsafeAdd( const char *key,
435                             bool isStatic,
436                             HashKey hashedKey )
437{
438   JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
439   BucketIndex bucketIndex = hashedKey % bucketsSize_;
440   ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
441   ValueInternalLink *link = previousLink;
442   BucketIndex index;
443   for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
444   {
445      if ( link->items_[index].isItemAvailable() )
446         break;
447   }
448   if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
449   {
450      ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
451      index = 0;
452      link->next_ = newLink;
453      previousLink = newLink;
454      link = newLink;
455   }
456   return setNewItem( key, isStatic, link, index );
457}
458
459
460ValueInternalMap::HashKey
461ValueInternalMap::hash( const char *key ) const
462{
463   HashKey hash = 0;
464   while ( *key )
465      hash += *key++ * 37;
466   return hash;
467}
468
469
470int
471ValueInternalMap::compare( const ValueInternalMap &other ) const
472{
473   int sizeDiff( itemCount_ - other.itemCount_ );
474   if ( sizeDiff != 0 )
475      return sizeDiff;
476   // Strict order guaranty is required. Compare all keys FIRST, then compare values.
477   IteratorState it;
478   IteratorState itEnd;
479   makeBeginIterator( it );
480   makeEndIterator( itEnd );
481   for ( ; !equals(it,itEnd); increment(it) )
482   {
483      if ( !other.find( key( it ) ) )
484         return 1;
485   }
486
487   // All keys are equals, let's compare values
488   makeBeginIterator( it );
489   for ( ; !equals(it,itEnd); increment(it) )
490   {
491      const Value *otherValue = other.find( key( it ) );
492      int valueDiff = value(it).compare( *otherValue );
493      if ( valueDiff != 0 )
494         return valueDiff;
495   }
496   return 0;
497}
498
499
500void
501ValueInternalMap::makeBeginIterator( IteratorState &it ) const
502{
503   it.map_ = const_cast<ValueInternalMap *>( this );
504   it.bucketIndex_ = 0;
505   it.itemIndex_ = 0;
506   it.link_ = buckets_;
507}
508
509
510void
511ValueInternalMap::makeEndIterator( IteratorState &it ) const
512{
513   it.map_ = const_cast<ValueInternalMap *>( this );
514   it.bucketIndex_ = bucketsSize_;
515   it.itemIndex_ = 0;
516   it.link_ = 0;
517}
518
519
520bool
521ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
522{
523   return x.map_ == other.map_
524          &&  x.bucketIndex_ == other.bucketIndex_
525          &&  x.link_ == other.link_
526          &&  x.itemIndex_ == other.itemIndex_;
527}
528
529
530void
531ValueInternalMap::incrementBucket( IteratorState &iterator )
532{
533   ++iterator.bucketIndex_;
534   JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
535      "ValueInternalMap::increment(): attempting to iterate beyond end." );
536   if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
537      iterator.link_ = 0;
538   else
539      iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
540   iterator.itemIndex_ = 0;
541}
542
543
544void
545ValueInternalMap::increment( IteratorState &iterator )
546{
547   JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
548   ++iterator.itemIndex_;
549   if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
550   {
551      JSON_ASSERT_MESSAGE( iterator.link_ != 0,
552         "ValueInternalMap::increment(): attempting to iterate beyond end." );
553      iterator.link_ = iterator.link_->next_;
554      if ( iterator.link_ == 0 )
555         incrementBucket( iterator );
556   }
557   else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
558   {
559      incrementBucket( iterator );
560   }
561}
562
563
564void
565ValueInternalMap::decrement( IteratorState &iterator )
566{
567   if ( iterator.itemIndex_ == 0 )
568   {
569      JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
570      if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
571      {
572         JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
573         --(iterator.bucketIndex_);
574      }
575      iterator.link_ = iterator.link_->previous_;
576      iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
577   }
578}
579
580
581const char *
582ValueInternalMap::key( const IteratorState &iterator )
583{
584   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
585   return iterator.link_->keys_[iterator.itemIndex_];
586}
587
588const char *
589ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
590{
591   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
592   isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
593   return iterator.link_->keys_[iterator.itemIndex_];
594}
595
596
597Value &
598ValueInternalMap::value( const IteratorState &iterator )
599{
600   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
601   return iterator.link_->items_[iterator.itemIndex_];
602}
603
604
605int
606ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
607{
608   int offset = 0;
609   IteratorState it = x;
610   while ( !equals( it, y ) )
611      increment( it );
612   return offset;
613}
614
615} // namespace Json
616