2 * Copyright 2001 Adrian Thurston <thurston@cs.queensu.ca>
5 /* This file is part of Aapl.
7 * Aapl is free software; you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free
9 * Software Foundation; either version 2.1 of the License, or (at your option)
12 * Aapl is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with Aapl; if not, write to the Free Software Foundation, Inc., 59
19 * Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /* This header is not wrapped in ifndefs because it is
23 * not intended to be included by users directly. */
29 /* Binary Search Table */
30 template < BST_TEMPL_DECLARE
> class BstTable
:
32 public Vector
< Element
, Resize
>
34 typedef Vector
<Element
, Resize
> BaseVector
;
35 typedef Table
<Element
> BaseTable
;
39 * \brief Default constructor.
41 * Create an empty binary search table.
46 * \brief Construct with initial value.
48 * Constructs a binary search table with an initial item. Uses the default
49 * constructor for initializing Value.
51 BstTable(const Key
&key
)
56 * \brief Construct with initial value.
58 * Constructs a binary search table with an initial key/value pair.
60 BstTable(const Key
&key
, const Value
&val
)
64 #if ! defined( BSTSET )
66 * \brief Construct with initial value.
68 * Constructs a binary search table with an initial Element.
70 BstTable(const Element
&el
)
74 Element
*insert(const Key
&key
, Element
**lastFound
= 0);
75 Element
*insertMulti(const Key
&key
);
77 bool insert(const BstTable
&other
);
78 void insertMulti(const BstTable
&other
);
81 Element
*insert(const Key
&key
, const Value
&val
,
82 Element
**lastFound
= 0);
83 Element
*insertMulti(const Key
&key
, const Value
&val
);
86 #if ! defined( BSTSET )
87 Element
*insert(const Element
&el
, Element
**lastFound
= 0);
88 Element
*insertMulti(const Element
&el
);
91 Element
*find(const Key
&key
, Element
**lastFound
= 0) const;
92 bool findMulti( const Key
&key
, Element
*&lower
,
93 Element
*&upper
) const;
95 bool remove(const Key
&key
);
96 bool remove(Element
*item
);
97 long removeMulti(const Key
&key
);
98 long removeMulti(Element
*lower
, Element
*upper
);
100 /* The following provide access to the underlying insert and remove
101 * functions that my be hidden by the BST insert and remove. The insertDup
102 * and insertNew functions will never be hidden. They are provided for
103 * consistency. The difference between the non-shared and the shared
104 * tables is the documentation reference to the invoked function. */
106 #if !defined( SHARED_BST )
109 /** \brief Call the insert of the underlying vector.
111 * Provides to access to the vector insert, which may become hidden. Care
112 * should be taken to ensure that after the insert the ordering of
113 * elements is preserved.
114 * Invokes Vector::insert( long pos, const T &val ).
116 void vinsert(long pos
, const Element
&val
)
117 { Vector
< Element
, Resize
>::insert( pos
, &val
, 1 ); }
119 /** \brief Call the insert of the underlying vector.
121 * Provides to access to the vector insert, which may become hidden. Care
122 * should be taken to ensure that after the insert the ordering of
123 * elements is preserved.
124 * Invokes Vector::insert( long pos, const T *val, long len ).
126 void vinsert(long pos
, const Element
*val
, long len
)
127 { Vector
< Element
, Resize
>::insert( pos
, val
, len
); }
129 /** \brief Call the insert of the underlying vector.
131 * Provides to access to the vector insert, which may become hidden. Care
132 * should be taken to ensure that after the insert the ordering of
133 * elements is preserved.
134 * Invokes Vector::insert( long pos, const Vector &v ).
136 void vinsert(long pos
, const BstTable
&v
)
137 { Vector
< Element
, Resize
>::insert( pos
, v
.data
, v
.tabLen
); }
143 /** \brief Call the remove of the underlying vector.
145 * Provides access to the vector remove, which may become hidden.
146 * Invokes Vector::remove( long pos ).
148 void vremove(long pos
)
149 { Vector
< Element
, Resize
>::remove( pos
, 1 ); }
151 /** \brief Call the remove of the underlying vector.
153 * Proves access to the vector remove, which may become hidden.
154 * Invokes Vector::remove( long pos, long len ).
156 void vremove(long pos
, long len
)
157 { Vector
< Element
, Resize
>::remove( pos
, len
); }
160 #else /* SHARED_BST */
163 /** \brief Call the insert of the underlying vector.
165 * Provides to access to the vector insert, which may become hidden. Care
166 * should be taken to ensure that after the insert the ordering of
167 * elements is preserved.
168 * Invokes SVector::insert( long pos, const T &val ).
170 void vinsert(long pos
, const Element
&val
)
171 { Vector
< Element
, Resize
>::insert( pos
, &val
, 1 ); }
173 /** \brief Call the insert of the underlying vector.
175 * Provides to access to the vector insert, which may become hidden. Care
176 * should be taken to ensure that after the insert the ordering of
177 * elements is preserved.
178 * Invokes SVector::insert( long pos, const T *val, long len ).
180 void vinsert(long pos
, const Element
*val
, long len
)
181 { Vector
< Element
, Resize
>::insert( pos
, val
, len
); }
183 /** \brief Call the insert of the underlying vector.
185 * Provides to access to the vector insert, which may become hidden. Care
186 * should be taken to ensure that after the insert the ordering of
187 * elements is preserved.
188 * Invokes SVector::insert( long pos, const SVector &v ).
190 void vinsert(long pos
, const BstTable
&v
)
191 { Vector
< Element
, Resize
>::insert( pos
, v
.data
, v
.length() ); }
197 /** \brief Call the remove of the underlying vector.
199 * Provides access to the vector remove, which may become hidden.
200 * Invokes SVector::remove( long pos ).
202 void vremove(long pos
)
203 { Vector
< Element
, Resize
>::remove( pos
, 1 ); }
205 /** \brief Call the remove of the underlying vector.
207 * Proves access to the vector remove, which may become hidden.
208 * Invokes SVector::remove( long pos, long len ).
210 void vremove(long pos
, long len
)
211 { Vector
< Element
, Resize
>::remove( pos
, len
); }
215 #endif /* SHARED_BST */
220 #if defined( SHARED_BST )
222 * \brief Construct a binary search table with an initial amount of
225 * The table is initialized to have room for allocLength elements. The
226 * table starts empty.
228 template <BST_TEMPL_DEF
> BstTable
<BST_TEMPL_USE
>::
229 BstTable( long allocLen
)
231 /* Allocate the space if we are given a positive allocLen. */
232 if ( allocLen
> 0 ) {
233 /* Allocate the data needed. */
234 STabHead
*head
= (STabHead
*)
235 malloc( sizeof(STabHead
) + sizeof(Element
) * allocLen
);
237 throw std::bad_alloc();
239 /* Set up the header and save the data pointer. */
241 head
->allocLen
= allocLen
;
243 BaseTable::data
= (Element
*) (head
+ 1);
248 * \brief Construct a binary search table with an initial amount of
251 * The table is initialized to have room for allocLength elements. The
252 * table starts empty.
254 template <BST_TEMPL_DEF
> BstTable
<BST_TEMPL_USE
>::
255 BstTable( long allocLen
)
257 /* Allocate the space if we are given a positive allocLen. */
258 BaseTable::allocLen
= allocLen
;
259 if ( BaseTable::allocLen
> 0 ) {
260 BaseTable::data
= (Element
*) malloc(sizeof(Element
) * BaseTable::allocLen
);
261 if ( BaseTable::data
== NULL
)
262 throw std::bad_alloc();
270 * \brief Find the element with the given key and remove it.
272 * If multiple elements with the given key exist, then it is unspecified which
273 * element will be removed.
275 * \returns True if an element is found and consequently removed, false
278 template <BST_TEMPL_DEF
> bool BstTable
<BST_TEMPL_USE
>::
279 remove(const Key
&key
)
281 Element
*el
= find(key
);
283 Vector
< Element
>::remove(el
- BaseTable::data
);
290 * \brief Remove the element pointed to by item.
292 * If item does not point to an element in the tree, then undefined behaviour
293 * results. If item is null, then remove has no effect.
295 * \returns True if item is not null, false otherwise.
297 template <BST_TEMPL_DEF
> bool BstTable
<BST_TEMPL_USE
>::
298 remove( Element
*item
)
301 Vector
< Element
>::remove(item
- BaseTable::data
);
308 * \brief Find and remove the entire range of elements with the given key.
310 * \returns The number of elements removed.
312 template <BST_TEMPL_DEF
> long BstTable
<BST_TEMPL_USE
>::
313 removeMulti(const Key
&key
)
316 if ( findMulti(key
, low
, high
) ) {
317 /* Get the length of the range. */
318 long num
= high
- low
+ 1;
319 Vector
< Element
>::remove(low
- BaseTable::data
, num
);
326 template <BST_TEMPL_DEF
> long BstTable
<BST_TEMPL_USE
>::
327 removeMulti(Element
*lower
, Element
*upper
)
329 /* Get the length of the range. */
330 long num
= upper
- lower
+ 1;
331 Vector
< Element
>::remove(lower
- BaseTable::data
, num
);
337 * \brief Find a range of elements with the given key.
339 * If any elements with the given key exist then lower and upper are set to
340 * the low and high ends of the continous range of elements with the key.
341 * Lower and upper will point to the first and last elements with the key.
343 * \returns True if any elements are found, false otherwise.
345 template <BST_TEMPL_DEF
> bool BstTable
<BST_TEMPL_USE
>::
346 findMulti(const Key
&key
, Element
*&low
, Element
*&high
) const
348 const Element
*lower
, *mid
, *upper
;
350 const long tblLen
= BaseTable::length();
352 if ( BaseTable::data
== 0 )
355 lower
= BaseTable::data
;
356 upper
= BaseTable::data
+ tblLen
- 1;
358 if ( upper
< lower
) {
359 /* Did not find the fd in the array. */
363 mid
= lower
+ ((upper
-lower
)>>1);
364 keyRelation
= compare(key
, GET_KEY(*mid
));
366 if ( keyRelation
< 0 )
368 else if ( keyRelation
> 0 )
371 Element
*lowEnd
= BaseTable::data
- 1;
372 Element
*highEnd
= BaseTable::data
+ tblLen
;
375 while ( lower
!= lowEnd
&&
376 compare(key
, GET_KEY(*lower
)) == 0 )
380 while ( upper
!= highEnd
&&
381 compare(key
, GET_KEY(*upper
)) == 0 )
384 low
= (Element
*)lower
+ 1;
385 high
= (Element
*)upper
- 1;
392 * \brief Find an element with the given key.
394 * If the find succeeds then lastFound is set to the element found. If the
395 * find fails then lastFound is set the location where the key would be
396 * inserted. If there is more than one element in the tree with the given key,
397 * then it is unspecified which element is returned as the match.
399 * \returns The element found on success, null on failure.
401 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
402 find( const Key
&key
, Element
**lastFound
) const
404 const Element
*lower
, *mid
, *upper
;
406 const long tblLen
= BaseTable::length();
408 if ( BaseTable::data
== 0 )
411 lower
= BaseTable::data
;
412 upper
= BaseTable::data
+ tblLen
- 1;
414 if ( upper
< lower
) {
415 /* Did not find the key. Last found gets the insert location. */
416 if ( lastFound
!= 0 )
417 *lastFound
= (Element
*)lower
;
421 mid
= lower
+ ((upper
-lower
)>>1);
422 keyRelation
= compare(key
, GET_KEY(*mid
));
424 if ( keyRelation
< 0 )
426 else if ( keyRelation
> 0 )
429 /* Key is found. Last found gets the found record. */
430 if ( lastFound
!= 0 )
431 *lastFound
= (Element
*)mid
;
432 return (Element
*)mid
;
437 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
438 insert(const Key
&key
, Element
**lastFound
)
440 const Element
*lower
, *mid
, *upper
;
441 long keyRelation
, insertPos
;
442 const long tblLen
= BaseTable::length();
445 /* If the table is empty then go straight to insert. */
446 lower
= BaseTable::data
;
450 lower
= BaseTable::data
;
451 upper
= BaseTable::data
+ tblLen
- 1;
453 if ( upper
< lower
) {
454 /* Did not find the key in the array.
455 * Place to insert at is lower. */
459 mid
= lower
+ ((upper
-lower
)>>1);
460 keyRelation
= compare(key
, GET_KEY(*mid
));
462 if ( keyRelation
< 0 )
464 else if ( keyRelation
> 0 )
467 if ( lastFound
!= 0 )
468 *lastFound
= (Element
*)mid
;
474 /* Get the insert pos. */
475 insertPos
= lower
- BaseTable::data
;
477 /* Do the insert. After makeRawSpaceFor, lower pointer is no good. */
478 BaseVector::makeRawSpaceFor(insertPos
, 1);
479 new(BaseTable::data
+ insertPos
) Element(key
);
482 if ( lastFound
!= 0 )
483 *lastFound
= BaseTable::data
+ insertPos
;
484 return BaseTable::data
+ insertPos
;
488 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
489 insertMulti(const Key
&key
)
491 const Element
*lower
, *mid
, *upper
;
492 long keyRelation
, insertPos
;
493 const long tblLen
= BaseTable::length();
496 /* If the table is empty then go straight to insert. */
497 lower
= BaseTable::data
;
501 lower
= BaseTable::data
;
502 upper
= BaseTable::data
+ tblLen
- 1;
504 if ( upper
< lower
) {
505 /* Did not find the key in the array.
506 * Place to insert at is lower. */
510 mid
= lower
+ ((upper
-lower
)>>1);
511 keyRelation
= compare(key
, GET_KEY(*mid
));
513 if ( keyRelation
< 0 )
515 else if ( keyRelation
> 0 )
524 /* Get the insert pos. */
525 insertPos
= lower
- BaseTable::data
;
528 BaseVector::makeRawSpaceFor(insertPos
, 1);
529 new(BaseTable::data
+ insertPos
) Element(key
);
531 /* Return the element inserted. */
532 return BaseTable::data
+ insertPos
;
536 * \brief Insert each element from other.
538 * Always attempts to insert all elements even if the insert of some item from
541 * \returns True if all items inserted successfully, false if any insert
544 template <BST_TEMPL_DEF
> bool BstTable
<BST_TEMPL_USE
>::
545 insert(const BstTable
&other
)
547 bool allSuccess
= true;
548 long otherLen
= other
.length();
549 for ( long i
= 0; i
< otherLen
; i
++ ) {
550 Element
*el
= insert( other
.data
[i
] );
558 * \brief Insert each element from other even if the elements exist already.
560 * No individual insertMulti can fail.
562 template <BST_TEMPL_DEF
> void BstTable
<BST_TEMPL_USE
>::
563 insertMulti(const BstTable
&other
)
565 long otherLen
= other
.length();
566 for ( long i
= 0; i
< otherLen
; i
++ )
567 insertMulti( other
.data
[i
] );
570 #if ! defined( BSTSET )
573 * \brief Insert the given element.
575 * If the key in the given element does not already exist in the table then a
576 * new element is inserted. They element copy constructor is used to place the
577 * element into the table. If lastFound is given, it is set to the new element
578 * created. If the insert fails then lastFound is set to the existing element
581 * \returns The new element created upon success, null upon failure.
583 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
584 insert(const Element
&el
, Element
**lastFound
)
586 const Element
*lower
, *mid
, *upper
;
587 long keyRelation
, insertPos
;
588 const long tblLen
= BaseTable::length();
591 /* If the table is empty then go straight to insert. */
592 lower
= BaseTable::data
;
596 lower
= BaseTable::data
;
597 upper
= BaseTable::data
+ tblLen
- 1;
599 if ( upper
< lower
) {
600 /* Did not find the key in the array.
601 * Place to insert at is lower. */
605 mid
= lower
+ ((upper
-lower
)>>1);
606 keyRelation
= compare(GET_KEY(el
), GET_KEY(*mid
));
608 if ( keyRelation
< 0 )
610 else if ( keyRelation
> 0 )
613 if ( lastFound
!= 0 )
614 *lastFound
= (Element
*)mid
;
620 /* Get the insert pos. */
621 insertPos
= lower
- BaseTable::data
;
623 /* Do the insert. After makeRawSpaceFor, lower pointer is no good. */
624 BaseVector::makeRawSpaceFor(insertPos
, 1);
625 new(BaseTable::data
+ insertPos
) Element(el
);
628 if ( lastFound
!= 0 )
629 *lastFound
= BaseTable::data
+ insertPos
;
630 return BaseTable::data
+ insertPos
;
634 * \brief Insert the given element even if it exists already.
636 * If the key in the given element exists already then the new element is
637 * placed next to some other element of the same key. InsertMulti cannot fail.
638 * The element copy constructor is used to place the element in the table.
640 * \returns The new element created.
642 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
643 insertMulti(const Element
&el
)
645 const Element
*lower
, *mid
, *upper
;
646 long keyRelation
, insertPos
;
647 const long tblLen
= BaseTable::length();
650 /* If the table is empty then go straight to insert. */
651 lower
= BaseTable::data
;
655 lower
= BaseTable::data
;
656 upper
= BaseTable::data
+ tblLen
- 1;
658 if ( upper
< lower
) {
659 /* Did not find the fd in the array.
660 * Place to insert at is lower. */
664 mid
= lower
+ ((upper
-lower
)>>1);
665 keyRelation
= compare(GET_KEY(el
), GET_KEY(*mid
));
667 if ( keyRelation
< 0 )
669 else if ( keyRelation
> 0 )
678 /* Get the insert pos. */
679 insertPos
= lower
- BaseTable::data
;
682 BaseVector::makeRawSpaceFor(insertPos
, 1);
683 new(BaseTable::data
+ insertPos
) Element(el
);
685 /* Return the element inserted. */
686 return BaseTable::data
+ insertPos
;
691 #if defined( BSTMAP )
694 * \brief Insert the given key-value pair.
696 * If the given key does not already exist in the table then the key-value
697 * pair is inserted. Copy constructors are used to place the pair in the
698 * table. If lastFound is given, it is set to the new entry created. If the
699 * insert fails then lastFound is set to the existing pair of the same key.
701 * \returns The new element created upon success, null upon failure.
703 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
704 insert(const Key
&key
, const Value
&val
, Element
**lastFound
)
706 const Element
*lower
, *mid
, *upper
;
707 long keyRelation
, insertPos
;
708 const long tblLen
= BaseTable::length();
711 /* If the table is empty then go straight to insert. */
712 lower
= BaseTable::data
;
716 lower
= BaseTable::data
;
717 upper
= BaseTable::data
+ tblLen
- 1;
719 if ( upper
< lower
) {
720 /* Did not find the fd in the array.
721 * Place to insert at is lower. */
725 mid
= lower
+ ((upper
-lower
)>>1);
726 keyRelation
= Compare::compare(key
, mid
->key
);
728 if ( keyRelation
< 0 )
730 else if ( keyRelation
> 0 )
733 if ( lastFound
!= NULL
)
734 *lastFound
= (Element
*)mid
;
740 /* Get the insert pos. */
741 insertPos
= lower
- BaseTable::data
;
744 BaseVector::makeRawSpaceFor(insertPos
, 1);
745 new(BaseTable::data
+ insertPos
) Element(key
, val
);
748 if ( lastFound
!= NULL
)
749 *lastFound
= BaseTable::data
+ insertPos
;
750 return BaseTable::data
+ insertPos
;
755 * \brief Insert the given key-value pair even if the key exists already.
757 * If the key exists already then the key-value pair is placed next to some
758 * other pair of the same key. InsertMulti cannot fail. Copy constructors are
759 * used to place the pair in the table.
761 * \returns The new element created.
763 template <BST_TEMPL_DEF
> Element
*BstTable
<BST_TEMPL_USE
>::
764 insertMulti(const Key
&key
, const Value
&val
)
766 const Element
*lower
, *mid
, *upper
;
767 long keyRelation
, insertPos
;
768 const long tblLen
= BaseTable::length();
771 /* If the table is empty then go straight to insert. */
772 lower
= BaseTable::data
;
776 lower
= BaseTable::data
;
777 upper
= BaseTable::data
+ tblLen
- 1;
779 if ( upper
< lower
) {
780 /* Did not find the key in the array.
781 * Place to insert at is lower. */
785 mid
= lower
+ ((upper
-lower
)>>1);
786 keyRelation
= Compare::compare(key
, mid
->key
);
788 if ( keyRelation
< 0 )
790 else if ( keyRelation
> 0 )
799 /* Get the insert pos. */
800 insertPos
= lower
- BaseTable::data
;
803 BaseVector::makeRawSpaceFor(insertPos
, 1);
804 new(BaseTable::data
+ insertPos
) Element(key
, val
);
806 /* Return the element inserted. */
807 return BaseTable::data
+ insertPos
;
812 #ifdef AAPL_NAMESPACE