1 /*
2    Copyright (C) 2005, 2006 MySQL AB
3     All rights reserved. Use is subject to license terms.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License, version 2.0,
7    as published by the Free Software Foundation.
8 
9    This program is also distributed with certain software (including
10    but not limited to OpenSSL) that is licensed under separate terms,
11    as designated in a particular file or component or in included license
12    documentation.  The authors of MySQL hereby grant you an additional
13    permission to link the program and your derivative works with the
14    separately licensed software that they have included with MySQL.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License, version 2.0, for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 */
25 
26 #ifndef LINEAR_POOL_HPP
27 #define LINEAR_POOL_HPP
28 
29 #include <Bitmask.hpp>
30 #include "SuperPool.hpp"
31 
32 /*
33  * LinearPool - indexed record pool
34  *
35  * LinearPool implements a pool where each record has a 0-based index.
36  * Any index value (up to 2^32-1) is allowed.  Normal efficient usage is
37  * to assign index values in sequence and to re-use any values which
38  * have become free.  This is default seize/release behaviour.
39  *
40  * LinearPool has 2 internal RecordPool instances:
41  *
42  * (a) record pool of T (the template argument class)
43  * (b) record pool of "maps" (array of Uint32)
44  *
45  * The maps translate an index into an i-value in (a).  Each map has
46  * a level.  Level 0 maps point to i-values.  Level N+1 maps point to
47  * level N maps.  There is a unique "root map" at top.
48  *
49  * This works exactly like numbers in a given base.  Each map has base
50  * size entries.  For implementation convenience the base must be power
51  * of 2 between 2^1 and 2^15.  It is given by its log2 value (1-15).
52  *
53  * A position in a map is also called a "digit".
54  *
55  * There is a doubly linked list of available maps (some free entries)
56  * on each level.  There is a doubly linked freelist within each map.
57  * There is also a bitmask of used entries in each map.
58  *
59  * Level 0 free entry has space for one record.  Level N free entry
60  * implies space for base^N records.  The implied levels are created and
61  * removed on demand.  Empty maps are usually removed.
62  *
63  * Default base is 256 (log2 = 8) which requires maximum 4 levels or
64  * digits (similar to ip address).
65  *
66  * TODO
67  *
68  * - move most of the inline code to LinearPool.cpp
69  * - optimize for common case
70  * - add optimized 2-level implementation (?)
71  */
72 
73 #include "SuperPool.hpp"
74 
75 template <class T, Uint32 LogBase = 8>
76 class LinearPool {
77   typedef SuperPool::PtrI PtrI;
78 
79   // Base.
80   STATIC_CONST( Base = 1 << LogBase );
81 
82   // Digit mask.
83   STATIC_CONST( DigitMask = Base - 1 );
84 
85   // Max possible levels (0 to max root level).
86   STATIC_CONST( MaxLevels = (32 + LogBase - 1) / LogBase );
87 
88   // Number of words in map used bit mask.
89   STATIC_CONST( BitmaskSize = (Base + 31) / 32 );
90 
91   // Map.
92   struct Map {
93     Uint32 m_level;
94     Uint32 m_occup;     // number of used entries
95     Uint32 m_firstfree; // position of first free entry
96     PtrI m_parent;      // parent map
97     Uint32 m_index;     // from root to here
98     PtrI m_nextavail;
99     PtrI m_prevavail;
100     Uint32 m_bitmask[BitmaskSize];
101     PtrI m_entry[Base];
102   };
103 
104 public:
105 
106   // Constructor.
107   LinearPool(GroupPool& gp);
108 
109   // Destructor.
110   ~LinearPool();
111 
112   // Update pointer ptr.p according to index value ptr.i.
113   void getPtr(Ptr<T>& ptr);
114 
115   // Allocate record from the pool.  Reuses free index if possible.
116   bool seize(Ptr<T>& ptr);
117 
118   // Allocate given index.  Like seize but returns -1 if in use.
119   int seize_index(Ptr<T>& ptr, Uint32 index);
120 
121   // Return record to the pool.
122   void release(Ptr<T>& ptr);
123 
124   // Return number of used records (may require 1 page scan).
125   Uint32 count();
126 
127   // Verify (debugging).
128   void verify();
129 
130 private:
131 
132   // Given index find the bottom map.
133   void get_map(Ptr<Map>& map_ptr, Uint32 index);
134 
135   // Add new root map and increase level
136   bool add_root();
137 
138   // Add new non-root map.
139   bool add_map(Ptr<Map>& map_ptr, Ptr<Map> parent_ptr, Uint32 digit);
140 
141   // Subroutine to initialize map free lists.
142   void init_free(Ptr<Map> map_ptr);
143 
144   // Add entry at given free position.
145   void add_entry(Ptr<Map> map_ptr, Uint32 digit, PtrI ptr_i);
146 
147   // Remove entry and map if it becomes empty.
148   void remove_entry(Ptr<Map> map_ptr, Uint32 digit);
149 
150   // Remove map and all parents which become empty.
151   void remove_map(Ptr<Map> map_ptr);
152 
153   // Add map to available list.
154   void add_avail(Ptr<Map> map_ptr);
155 
156   // Remove map from available list.
157   void remove_avail(Ptr<Map> map_ptr);
158 
159   // Verify available lists
160   void verify_avail();
161 
162   // Verify map (recursive).
163   void verify_map(Ptr<Map> map_ptr, Uint32 level, Uint32* count);
164 
165   RecordPool<T> m_records;
166   RecordPool<Map> m_maps;
167   Uint32 m_levels;              // 0 means empty pool
168   PtrI m_root;
169   PtrI m_avail[MaxLevels];
170 };
171 
172 template <class T, Uint32 LogBase>
173 inline
LinearPool(GroupPool & gp)174 LinearPool<T, LogBase>::LinearPool(GroupPool& gp) :
175   m_records(gp),
176   m_maps(gp),
177   m_levels(0),
178   m_root(RNIL)
179 {
180   Uint32 n;
181   for (n = 0; n < MaxLevels; n++)
182     m_avail[n] = RNIL;
183 }
184 
185 template <class T, Uint32 LogBase>
186 inline
~LinearPool()187 LinearPool<T, LogBase>::~LinearPool()
188 {
189 }
190 
191 template <class T, Uint32 LogBase>
192 inline void
getPtr(Ptr<T> & ptr)193 LinearPool<T, LogBase>::getPtr(Ptr<T>& ptr)
194 {
195   Uint32 index = ptr.i;
196   // get level 0 map
197   Ptr<Map> map_ptr;
198   get_map(map_ptr, index);
199   // get record
200   Ptr<T> rec_ptr;
201   Uint32 digit = index & DigitMask;
202   assert(BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
203   rec_ptr.i = map_ptr.p->m_entry[digit];
204   m_records.getPtr(rec_ptr);
205   ptr.p = rec_ptr.p;
206 }
207 
208 template <class T, Uint32 LogBase>
209 inline bool
seize(Ptr<T> & ptr)210 LinearPool<T, LogBase>::seize(Ptr<T>& ptr)
211 {
212   // look for free list on some level
213   Ptr<Map> map_ptr;
214   map_ptr.i = RNIL;
215   Uint32 n = 0;
216   while (n < m_levels) {
217     if ((map_ptr.i = m_avail[n]) != RNIL)
218       break;
219     n++;
220   }
221   if (map_ptr.i == RNIL) {
222     // add new level with available maps
223     if (! add_root())
224       return false;
225     assert(n < m_levels);
226     map_ptr.i = m_avail[n];
227   }
228   m_maps.getPtr(map_ptr);
229   // walk down creating missing levels and using an entry on each
230   Uint32 digit;
231   Ptr<Map> new_ptr;
232   new_ptr.i = RNIL;
233   while (true) {
234     digit = map_ptr.p->m_firstfree;
235     if (n == 0)
236       break;
237     Ptr<Map> child_ptr;
238     if (! add_map(child_ptr, map_ptr, digit)) {
239       if (new_ptr.i != RNIL)
240         remove_map(new_ptr);
241       return false;
242     }
243     new_ptr = child_ptr;
244     map_ptr = child_ptr;
245     n--;
246   }
247   // now on level 0
248   assert(map_ptr.p->m_level == 0);
249   Ptr<T> rec_ptr;
250   if (! m_records.seize(rec_ptr)) {
251     if (new_ptr.i != RNIL)
252       remove_map(new_ptr);
253     return false;
254   }
255   add_entry(map_ptr, digit, rec_ptr.i);
256   ptr.i = digit + (map_ptr.p->m_index << LogBase);
257   ptr.p = rec_ptr.p;
258   return true;
259 }
260 
261 template <class T, Uint32 LogBase>
262 inline int
seize_index(Ptr<T> & ptr,Uint32 index)263 LinearPool<T, LogBase>::seize_index(Ptr<T>& ptr, Uint32 index)
264 {
265   // extract all digits at least up to current root level
266   Uint32 digits[MaxLevels];
267   Uint32 n = 0;
268   Uint32 tmp = index;
269   do {
270     digits[n] = tmp & DigitMask;
271     tmp >>= LogBase;
272   } while (++n < m_levels || tmp != 0);
273   // add any new root levels
274   while (n > m_levels) {
275     if (! add_root())
276       return false;
277   }
278   // start from root
279   Ptr<Map> map_ptr;
280   map_ptr.i = m_root;
281   m_maps.getPtr(map_ptr);
282   // walk down creating or re-using existing levels
283   Uint32 digit;
284   bool used;
285   Ptr<Map> new_ptr;
286   new_ptr.i = RNIL;
287   while (true) {
288     digit = digits[--n];
289     used = BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit);
290     if (n == 0)
291       break;
292     if (used) {
293       map_ptr.i = map_ptr.p->m_entry[digit];
294       m_maps.getPtr(map_ptr);
295     } else {
296       Ptr<Map> child_ptr;
297       if (! add_map(child_ptr, map_ptr, digit)) {
298         if (new_ptr.i != RNIL)
299           remove_map(new_ptr);
300       }
301       new_ptr = child_ptr;
302       map_ptr = child_ptr;
303     }
304   }
305   // now at level 0
306   assert(map_ptr.p->m_level == 0);
307   Ptr<T> rec_ptr;
308   if (used || ! m_records.seize(rec_ptr)) {
309     if (new_ptr.i != RNIL)
310       remove_map(new_ptr);
311     return used ? -1 : false;
312   }
313   add_entry(map_ptr, digit, rec_ptr.i);
314   assert(index == digit + (map_ptr.p->m_index << LogBase));
315   ptr.i = index;
316   ptr.p = rec_ptr.p;
317   return true;
318 }
319 
320 template <class T, Uint32 LogBase>
321 inline void
release(Ptr<T> & ptr)322 LinearPool<T, LogBase>::release(Ptr<T>& ptr)
323 {
324   Uint32 index = ptr.i;
325   // get level 0 map
326   Ptr<Map> map_ptr;
327   get_map(map_ptr, index);
328   // release record
329   Ptr<T> rec_ptr;
330   Uint32 digit = index & DigitMask;
331   rec_ptr.i = map_ptr.p->m_entry[digit];
332   m_records.release(rec_ptr);
333   // remove entry
334   remove_entry(map_ptr, digit);
335   // null pointer
336   ptr.i = RNIL;
337   ptr.p = 0;
338 }
339 
340 template <class T, Uint32 LogBase>
341 inline Uint32
count()342 LinearPool<T, LogBase>::count()
343 {
344   SuperPool& sp = m_records.m_superPool;
345   Uint32 count1 = sp.getRecUseCount(m_records.m_recInfo);
346   return count1;
347 }
348 
349 template <class T, Uint32 LogBase>
350 inline void
verify()351 LinearPool<T, LogBase>::verify()
352 {
353   verify_avail();
354   if (m_root == RNIL) {
355     assert(m_levels == 0);
356     return;
357   }
358   assert(m_levels != 0);
359   Ptr<Map> map_ptr;
360   map_ptr.i = m_root;
361   m_maps.getPtr(map_ptr);
362   Uint32 count1 = count();
363   Uint32 count2 = 0;
364   verify_map(map_ptr, m_levels - 1, &count2);
365   assert(count1 == count2);
366 }
367 
368 // private methods
369 
370 template <class T, Uint32 LogBase>
371 inline void
get_map(Ptr<Map> & map_ptr,Uint32 index)372 LinearPool<T, LogBase>::get_map(Ptr<Map>& map_ptr, Uint32 index)
373 {
374   // root map must exist
375   Ptr<Map> tmp_ptr;
376   tmp_ptr.i = m_root;
377   m_maps.getPtr(tmp_ptr);
378   assert(tmp_ptr.p->m_level + 1 == m_levels);
379   // extract index digits up to current root level
380   Uint32 digits[MaxLevels];
381   Uint32 n = 0;
382   do {
383     digits[n] = index & DigitMask;
384     index >>= LogBase;
385   } while (++n < m_levels);
386   assert(index == 0);
387   // walk down indirect levels
388   while (--n > 0) {
389     tmp_ptr.i = tmp_ptr.p->m_entry[digits[n]];
390     m_maps.getPtr(tmp_ptr);
391   }
392   // level 0 map
393   assert(tmp_ptr.p->m_level == 0);
394   map_ptr = tmp_ptr;
395 }
396 
397 template <class T, Uint32 LogBase>
398 inline bool
add_root()399 LinearPool<T, LogBase>::add_root()
400 {
401   // new root
402   Ptr<Map> map_ptr;
403   if (! m_maps.seize(map_ptr))
404     return false;
405   Uint32 n = m_levels++;
406   assert(n < MaxLevels);
407   // set up
408   map_ptr.p->m_level = n;
409   map_ptr.p->m_parent = RNIL;
410   map_ptr.p->m_index = 0;
411   init_free(map_ptr);
412   // on level > 0 digit 0 points to old root
413   if (n > 0) {
414     Ptr<Map> old_ptr;
415     old_ptr.i = m_root;
416     m_maps.getPtr(old_ptr);
417     assert(old_ptr.p->m_parent == RNIL);
418     old_ptr.p->m_parent = map_ptr.i;
419     add_entry(map_ptr, 0, old_ptr.i);
420   }
421   // set new root
422   m_root = map_ptr.i;
423   return true;
424 }
425 
426 template <class T, Uint32 LogBase>
427 inline bool
add_map(Ptr<Map> & map_ptr,Ptr<Map> parent_ptr,Uint32 digit)428 LinearPool<T, LogBase>::add_map(Ptr<Map>& map_ptr, Ptr<Map> parent_ptr, Uint32 digit)
429 {
430   if (! m_maps.seize(map_ptr))
431     return false;
432   assert(parent_ptr.p->m_level != 0);
433   // set up
434   map_ptr.p->m_level = parent_ptr.p->m_level - 1;
435   map_ptr.p->m_parent = parent_ptr.i;
436   map_ptr.p->m_index = digit + (parent_ptr.p->m_index << LogBase);
437   init_free(map_ptr);
438   add_entry(parent_ptr, digit, map_ptr.i);
439   return true;
440 }
441 
442 template <class T, Uint32 LogBase>
443 inline void
init_free(Ptr<Map> map_ptr)444 LinearPool<T, LogBase>::init_free(Ptr<Map> map_ptr)
445 {
446   map_ptr.p->m_occup = 0;
447   map_ptr.p->m_firstfree = 0;
448   // freelist
449   Uint32 j;
450   Uint16 back = ZNIL;
451   for (j = 0; j < Base - 1; j++) {
452     map_ptr.p->m_entry[j] = back | ((j + 1) << 16);
453     back = j;
454   }
455   map_ptr.p->m_entry[j] = back | (ZNIL << 16);
456   // bitmask
457   BitmaskImpl::clear(BitmaskSize, map_ptr.p->m_bitmask);
458   // add to available
459   add_avail(map_ptr);
460 }
461 
462 template <class T, Uint32 LogBase>
463 inline void
add_entry(Ptr<Map> map_ptr,Uint32 digit,PtrI ptr_i)464 LinearPool<T, LogBase>::add_entry(Ptr<Map> map_ptr, Uint32 digit, PtrI ptr_i)
465 {
466   assert(map_ptr.p->m_occup < Base && digit < Base);
467   assert(! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
468   // unlink from freelist
469   Uint32 val = map_ptr.p->m_entry[digit];
470   Uint16 back = val & ZNIL;
471   Uint16 forw = val >> 16;
472   if (back != ZNIL) {
473     assert(back < Base);
474     map_ptr.p->m_entry[back] &= ZNIL;
475     map_ptr.p->m_entry[back] |= (forw << 16);
476   }
477   if (forw != ZNIL) {
478     assert(forw < Base);
479     map_ptr.p->m_entry[forw] &= (ZNIL << 16);
480     map_ptr.p->m_entry[forw] |= back;
481   }
482   if (back == ZNIL) {
483     map_ptr.p->m_firstfree = forw;
484   }
485   // set new value
486   map_ptr.p->m_entry[digit] = ptr_i;
487   map_ptr.p->m_occup++;
488   BitmaskImpl::set(BitmaskSize, map_ptr.p->m_bitmask, digit);
489   if (map_ptr.p->m_occup == Base)
490     remove_avail(map_ptr);
491 }
492 
493 template <class T, Uint32 LogBase>
494 inline void
remove_entry(Ptr<Map> map_ptr,Uint32 digit)495 LinearPool<T, LogBase>::remove_entry(Ptr<Map> map_ptr, Uint32 digit)
496 {
497   assert(map_ptr.p->m_occup != 0 && digit < Base);
498   assert(BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, digit));
499   // add to freelist
500   Uint32 firstfree = map_ptr.p->m_firstfree;
501   map_ptr.p->m_entry[digit] = ZNIL | (firstfree << 16);
502   if (firstfree != ZNIL) {
503     assert(firstfree < Base);
504     map_ptr.p->m_entry[firstfree] &= (ZNIL << 16);
505     map_ptr.p->m_entry[firstfree] |= digit;
506   }
507   map_ptr.p->m_firstfree = digit;
508   map_ptr.p->m_occup--;
509   BitmaskImpl::clear(BitmaskSize, map_ptr.p->m_bitmask, digit);
510   if (map_ptr.p->m_occup + 1 == Base)
511     add_avail(map_ptr);
512   else if (map_ptr.p->m_occup == 0)
513     remove_map(map_ptr);
514 }
515 
516 template <class T, Uint32 LogBase>
517 inline void
remove_map(Ptr<Map> map_ptr)518 LinearPool<T, LogBase>::remove_map(Ptr<Map> map_ptr)
519 {
520   assert(map_ptr.p->m_occup == 0);
521   remove_avail(map_ptr);
522   Ptr<Map> parent_ptr;
523   parent_ptr.i = map_ptr.p->m_parent;
524   Uint32 digit = map_ptr.p->m_index & DigitMask;
525   PtrI map_ptr_i = map_ptr.i;
526   m_maps.release(map_ptr);
527   if (m_root == map_ptr_i) {
528     assert(parent_ptr.i == RNIL);
529     Uint32 used = count();
530     assert(used == 0);
531     m_root = RNIL;
532     m_levels = 0;
533   }
534   if (parent_ptr.i != RNIL) {
535     m_maps.getPtr(parent_ptr);
536     // remove child entry (recursive)
537     remove_entry(parent_ptr, digit);
538   }
539 }
540 
541 template <class T, Uint32 LogBase>
542 inline void
add_avail(Ptr<Map> map_ptr)543 LinearPool<T, LogBase>::add_avail(Ptr<Map> map_ptr)
544 {
545   Uint32 n = map_ptr.p->m_level;
546   assert(n < m_levels);
547   map_ptr.p->m_nextavail = m_avail[n];
548   if (map_ptr.p->m_nextavail != RNIL) {
549     Ptr<Map> next_ptr;
550     next_ptr.i = map_ptr.p->m_nextavail;
551     m_maps.getPtr(next_ptr);
552     next_ptr.p->m_prevavail = map_ptr.i;
553   }
554   map_ptr.p->m_prevavail = RNIL;
555   m_avail[n] = map_ptr.i;
556 }
557 
558 template <class T, Uint32 LogBase>
559 inline void
remove_avail(Ptr<Map> map_ptr)560 LinearPool<T, LogBase>::remove_avail(Ptr<Map> map_ptr)
561 {
562   Uint32 n = map_ptr.p->m_level;
563   assert(n < m_levels);
564   if (map_ptr.p->m_nextavail != RNIL) {
565     Ptr<Map> next_ptr;
566     next_ptr.i = map_ptr.p->m_nextavail;
567     m_maps.getPtr(next_ptr);
568     next_ptr.p->m_prevavail = map_ptr.p->m_prevavail;
569   }
570   if (map_ptr.p->m_prevavail != RNIL) {
571     Ptr<Map> prev_ptr;
572     prev_ptr.i = map_ptr.p->m_prevavail;
573     m_maps.getPtr(prev_ptr);
574     prev_ptr.p->m_nextavail = map_ptr.p->m_nextavail;
575   }
576   if (map_ptr.p->m_prevavail == RNIL) {
577     m_avail[n] = map_ptr.p->m_nextavail;
578   }
579   map_ptr.p->m_nextavail = RNIL;
580   map_ptr.p->m_prevavail = RNIL;
581 }
582 
583 template <class T, Uint32 LogBase>
584 inline void
verify_avail()585 LinearPool<T, LogBase>::verify_avail()
586 {
587   // check available lists
588   for (Uint32 n = 0; n < MaxLevels; n++) {
589     Ptr<Map> map_ptr;
590     map_ptr.i = m_avail[n];
591     Uint32 back = RNIL;
592     while (map_ptr.i != RNIL) {
593       m_maps.getPtr(map_ptr);
594       assert(map_ptr.p->m_occup < Base);
595       assert(back == map_ptr.p->m_prevavail);
596       back = map_ptr.i;
597       map_ptr.i = map_ptr.p->m_nextavail;
598     }
599   }
600 }
601 
602 template <class T, Uint32 LogBase>
603 inline void
verify_map(Ptr<Map> map_ptr,Uint32 level,Uint32 * count)604 LinearPool<T, LogBase>::verify_map(Ptr<Map> map_ptr, Uint32 level, Uint32* count)
605 {
606   assert(level < MaxLevels);
607   assert(map_ptr.p->m_level == level);
608   // check freelist
609   {
610     Uint32 nused = BitmaskImpl::count(BitmaskSize, map_ptr.p->m_bitmask);
611     assert(nused <= Base);
612     assert(map_ptr.p->m_occup == nused);
613     Uint32 nfree = 0;
614     Uint32 j = map_ptr.p->m_firstfree;
615     Uint16 back = ZNIL;
616     while (j != ZNIL) {
617       assert(j < Base);
618       assert(! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, j));
619       Uint32 val = map_ptr.p->m_entry[j];
620       assert(back == (val & ZNIL));
621       back = j;
622       j = (val >> 16);
623       nfree++;
624     }
625     assert(nused + nfree == Base);
626   }
627   // check entries
628   {
629     for (Uint32 j = 0; j < Base; j++) {
630       bool free = ! BitmaskImpl::get(BitmaskSize, map_ptr.p->m_bitmask, j);
631       if (free)
632         continue;
633       if (level != 0) {
634         Ptr<Map> child_ptr;
635         child_ptr.i = map_ptr.p->m_entry[j];
636         m_maps.getPtr(child_ptr);
637         assert(child_ptr.p->m_parent == map_ptr.i);
638         assert(child_ptr.p->m_index == j + (map_ptr.p->m_index << LogBase));
639         verify_map(child_ptr, level - 1, count);
640       } else {
641         Ptr<T> rec_ptr;
642         rec_ptr.i = map_ptr.p->m_entry[j];
643         m_records.getPtr(rec_ptr);
644         (*count)++;
645       }
646     }
647   }
648   // check membership on available list
649   {
650     Ptr<Map> avail_ptr;
651     avail_ptr.i = m_avail[map_ptr.p->m_level];
652     bool found = false;
653     while (avail_ptr.i != RNIL) {
654       if (avail_ptr.i == map_ptr.i) {
655         found = true;
656         break;
657       }
658       m_maps.getPtr(avail_ptr);
659       avail_ptr.i = avail_ptr.p->m_nextavail;
660     }
661     assert(found == (map_ptr.p->m_occup < Base));
662   }
663 }
664 
665 #endif
666