| /* | |
| * Copyright Marian Vittek | |
| * SPDX-License-Identifier: BSD-2-Clause | |
| * | |
| * http://sglib.sourceforge.net/#license says "you can use Sglib under the terms | |
| * of any license defined as an open source license by the Open Source Initiative | |
| * (see http://www.opensource.org/)" | |
| */ | |
| /* | |
| This is SGLIB version 1.0.4 | |
| (C) by Marian Vittek, Bratislava, http://www.xref-tech.com/sglib, 2003-5 | |
| License Conditions: You can use a verbatim copy (including this | |
| copyright notice) of sglib freely in any project, commercial or not. | |
| You can also use derivative forms freely under terms of Open Source | |
| Software license or under terms of GNU Public License. If you need | |
| to use a derivative form in a commercial project, or you need sglib | |
| under any other license conditions, contact the author. | |
| */ | |
| #ifndef _SGLIB__h_ | |
| #define _SGLIB__h_ | |
| /* the assert is used exclusively to write unexpected error messages */ | |
| #include <assert.h> | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* - LEVEL - 0 INTERFACE - */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ------------------------------ STATIC ARRAYS ------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* | |
| Basic algorithms for sorting arrays. Multiple depending arrays can | |
| be rearranged using user defined 'elem_exchangers' | |
| */ | |
| /* HEAP - SORT (level 0) */ | |
| #define SGLIB_ARRAY_SINGLE_HEAP_SORT(type, a, max, comparator) {\ | |
| SGLIB_ARRAY_HEAP_SORT(type, a, max, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ | |
| } | |
| #define SGLIB_ARRAY_HEAP_SORT(type, a, max, comparator, elem_exchanger) {\ | |
| int _k_;\ | |
| for(_k_=(max)/2; _k_>=0; _k_--) {\ | |
| SGLIB___ARRAY_HEAP_DOWN(type, a, _k_, max, comparator, elem_exchanger);\ | |
| }\ | |
| for(_k_=(max)-1; _k_>=0; _k_--) {\ | |
| elem_exchanger(type, a, 0, _k_);\ | |
| SGLIB___ARRAY_HEAP_DOWN(type, a, 0, _k_, comparator, elem_exchanger);\ | |
| }\ | |
| } | |
| #define SGLIB___ARRAY_HEAP_DOWN(type, a, ind, max, comparator, elem_exchanger) {\ | |
| int _m_, _l_, _r_, _i_;\ | |
| _i_ = (ind);\ | |
| _m_ = _i_;\ | |
| do {\ | |
| _i_ = _m_;\ | |
| _l_ = 2*_i_+1;\ | |
| _r_ = _l_+1;\ | |
| if (_l_ < (max)){\ | |
| if (comparator(((a)[_m_]), ((a)[_l_])) < 0) _m_ = _l_;\ | |
| if (_r_ < (max)) {\ | |
| if (comparator(((a)[_m_]), ((a)[_r_])) < 0) _m_ = _r_;\ | |
| }\ | |
| }\ | |
| if (_m_ != _i_) {\ | |
| elem_exchanger(type, a, _i_, _m_);\ | |
| }\ | |
| } while (_m_ != _i_);\ | |
| } | |
| /* QUICK - SORT (level 0) */ | |
| #define SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator) {\ | |
| SGLIB_ARRAY_QUICK_SORT(type, a, max, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ | |
| } | |
| #define SGLIB_ARRAY_QUICK_SORT(type, a, max, comparator, elem_exchanger) {\ | |
| int _i_, _j_, _p_, _stacki_, _start_, _end_;\ | |
| /* can sort up to 2^64 elements */\ | |
| int _startStack_[64];\ | |
| int _endStack_[64];\ | |
| _startStack_[0] = 0;\ | |
| _endStack_[0] = (max);\ | |
| _stacki_ = 1;\ | |
| while (_stacki_ > 0) {\ | |
| _stacki_ --;\ | |
| _start_ = _startStack_[_stacki_];\ | |
| _end_ = _endStack_[_stacki_];\ | |
| while (_end_ - _start_ > 2) {\ | |
| _p_ = _start_;\ | |
| _i_ = _start_ + 1;\ | |
| _j_ = _end_ - 1;\ | |
| while (_i_<_j_) {\ | |
| for(; _i_<=_j_ && comparator(((a)[_i_]),((a)[_p_]))<=0; _i_++) ;\ | |
| if (_i_ > _j_) {\ | |
| /* all remaining elements lesseq than pivot */\ | |
| elem_exchanger(type, a, _j_, _p_);\ | |
| _i_ = _j_;\ | |
| } else {\ | |
| for(; _i_<=_j_ && comparator(((a)[_j_]),((a)[_p_]))>=0; _j_--) ;\ | |
| if (_i_ > _j_) {\ | |
| /* all remaining elements greater than pivot */\ | |
| elem_exchanger(type, a, _j_, _p_);\ | |
| _i_ = _j_;\ | |
| } else if (_i_ < _j_) {\ | |
| elem_exchanger(type, a, _i_, _j_);\ | |
| if (_i_+2 < _j_) {_i_++; _j_--;}\ | |
| else if (_i_+1 < _j_) _i_++;\ | |
| }\ | |
| }\ | |
| }\ | |
| /* O.K. i==j and pivot is on a[i] == a[j] */\ | |
| /* handle recursive calls without recursion */\ | |
| if (_i_-_start_ > 1 && _end_-_j_ > 1) {\ | |
| /* two recursive calls, use array-stack */\ | |
| if (_i_-_start_ < _end_-_j_-1) {\ | |
| _startStack_[_stacki_] = _j_+1;\ | |
| _endStack_[_stacki_] = _end_;\ | |
| _stacki_ ++;\ | |
| _end_ = _i_;\ | |
| } else {\ | |
| _startStack_[_stacki_] = _start_;\ | |
| _endStack_[_stacki_] = _i_;\ | |
| _stacki_ ++;\ | |
| _start_ = _j_+1;\ | |
| }\ | |
| } else {\ | |
| if (_i_-_start_ > 1) {\ | |
| _end_ = _i_;\ | |
| } else {\ | |
| _start_ = _j_+1;\ | |
| }\ | |
| }\ | |
| }\ | |
| if (_end_ - _start_ == 2) {\ | |
| if (comparator(((a)[_start_]),((a)[_end_-1])) > 0) {\ | |
| elem_exchanger(type, a, _start_, _end_-1);\ | |
| }\ | |
| }\ | |
| }\ | |
| } | |
| /* BINARY SEARCH (level 0) */ | |
| #define SGLIB_ARRAY_BINARY_SEARCH(type, a, start_index, end_index, key, comparator, found, result_index) {\ | |
| int _kk_, _cc_, _ii_, _jj_, _ff_;\ | |
| _ii_ = (start_index);\ | |
| _jj_ = (end_index);\ | |
| _ff_ = 0;\ | |
| while (_ii_ <= _jj_ && _ff_==0) {\ | |
| _kk_ = (_jj_+_ii_)/2;\ | |
| _cc_ = comparator(((a)[_kk_]), (key));\ | |
| if (_cc_ == 0) {\ | |
| (result_index) = _kk_;\ | |
| _ff_ = 1;\ | |
| } else if (_cc_ < 0) {\ | |
| _ii_ = _kk_+1;\ | |
| } else {\ | |
| _jj_ = _kk_-1;\ | |
| }\ | |
| }\ | |
| if (_ff_ == 0) {\ | |
| /* not found, but set its resulting place in the array */\ | |
| (result_index) = _jj_+1;\ | |
| }\ | |
| (found) = _ff_;\ | |
| } | |
| /* -------------------------------- queue (in an array) ------------------ */ | |
| /* queue is a quadruple (a,i,j,dim) such that: */ | |
| /* a is the array storing values */ | |
| /* i is the index of the first used element in the array */ | |
| /* j is the index of the first free element in the array */ | |
| /* dim is the size of the array a */ | |
| /* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ | |
| #define SGLIB_QUEUE_INIT(type, a, i, j) { i = j = 0; } | |
| #define SGLIB_QUEUE_IS_EMPTY(type, a, i, j) ((i)==(j)) | |
| #define SGLIB_QUEUE_IS_FULL(type, a, i, j, dim) ((i)==((j)+1)%(dim)) | |
| #define SGLIB_QUEUE_FIRST_ELEMENT(type, a, i, j) (a[i]) | |
| #define SGLIB_QUEUE_ADD_NEXT(type, a, i, j, dim) {\ | |
| if (SGLIB_QUEUE_IS_FULL(type, a, i, j, dim)) assert(0 && "the queue is full");\ | |
| (j) = ((j)+1) % (dim);\ | |
| } | |
| #define SGLIB_QUEUE_ADD(type, a, elem, i, j, dim) {\ | |
| a[j] = (elem);\ | |
| SGLIB_QUEUE_ADD_NEXT(type, a, i, j, dim);\ | |
| } | |
| #define SGLIB_QUEUE_DELETE_FIRST(type, a, i, j, dim) {\ | |
| if (SGLIB_QUEUE_IS_EMPTY(type, a, i, j)) assert(0 && "the queue is empty");\ | |
| (i) = ((i)+1) % (dim);\ | |
| } | |
| #define SGLIB_QUEUE_DELETE(type, a, i, j, dim) {\ | |
| SGLIB_QUEUE_DELETE_FIRST(type, a, i, j, dim);\ | |
| } | |
| /* ----------------- priority queue (heap) (in an array) -------------------- */ | |
| /* heap is a triple (a,i,dim) such that: */ | |
| /* a is the array storing values */ | |
| /* i is the index of the first free element in the array */ | |
| /* dim is the size of the array a */ | |
| /* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ | |
| #define SGLIB_HEAP_INIT(type, a, i) { i = 0; } | |
| #define SGLIB_HEAP_IS_EMPTY(type, a, i) ((i)==0) | |
| #define SGLIB_HEAP_IS_FULL(type, a, i, dim) ((i)==(dim)) | |
| #define SGLIB_HEAP_FIRST_ELEMENT(type, a, i) (a[0]) | |
| #define SGLIB_HEAP_ADD_NEXT(type, a, i, dim, comparator, elem_exchanger) {\ | |
| int _i_;\ | |
| if (SGLIB_HEAP_IS_FULL(type, a, i, dim)) assert(0 && "the heap is full");\ | |
| _i_ = (i)++;\ | |
| while (_i_ > 0 && comparator(a[_i_/2], a[_i_]) < 0) {\ | |
| elem_exchanger(type, a, (_i_/2), _i_);\ | |
| _i_ = _i_/2;\ | |
| }\ | |
| } | |
| #define SGLIB_HEAP_ADD(type, a, elem, i, dim, comparator) {\ | |
| if (SGLIB_HEAP_IS_FULL(type, a, i, dim)) assert(0 && "the heap is full");\ | |
| a[i] = (elem);\ | |
| SGLIB_HEAP_ADD_NEXT(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ | |
| } | |
| #define SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, elem_exchanger) {\ | |
| if (SGLIB_HEAP_IS_EMPTY(type, a, i)) assert(0 && "the heap is empty");\ | |
| (i)--;\ | |
| a[0] = a[i];\ | |
| SGLIB___ARRAY_HEAP_DOWN(type, a, 0, i, comparator, elem_exchanger);\ | |
| } | |
| #define SGLIB_HEAP_DELETE(type, a, i, dim, comparator) {\ | |
| SGLIB_HEAP_DELETE_FIRST(type, a, i, dim, comparator, SGLIB_ARRAY_ELEMENTS_EXCHANGER);\ | |
| } | |
| /* ----------------- hashed table of pointers (in an array) -------------------- */ | |
| /* | |
| This hashed table is storing pointers to objects (not containers). | |
| In this table there is a one-to-one mapping between 'objects' stored | |
| in the table and indexes where they are placed. Each index is | |
| pointing to exactly one 'object' and each 'object' stored in the | |
| table occurs on exactly one index. Once an object is stored in the | |
| table, it can be represented via its index. | |
| In case of collision while adding an object the index shifted | |
| by SGLIB_HASH_TAB_SHIFT_CONSTANT (constant can be redefined) | |
| You can NOT delete an element from such hash table. The only | |
| justification (I can see) for this data structure is an exchange | |
| file format, having an index table at the beginning and then | |
| refering objects via indexes. | |
| !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! | |
| */ | |
| #define SGLIB_HASH_TAB_INIT(type, table, dim) {\ | |
| int _i_;\ | |
| for(_i_ = 0; _i_ < (dim); _i_++) (table)[_i_] = NULL;\ | |
| } | |
| #define SGLIB_HASH_TAB_ADD_IF_NOT_MEMBER(type, table, dim, elem, hash_function, comparator, member){\ | |
| unsigned _pos_;\ | |
| type *_elem_;\ | |
| SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, _pos_, _elem_);\ | |
| (member) = (table)[_pos_];\ | |
| if (_elem_ == NULL) {\ | |
| if ((table)[_pos_] != NULL) assert(0 && "the hash table is full");\ | |
| (table)[_pos_] = (elem);\ | |
| }\ | |
| } | |
| #define SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, hash_function, comparator, resultIndex, resultMember) {\ | |
| unsigned _i_;\ | |
| int _count_;\ | |
| type *_e_;\ | |
| _count = 0;\ | |
| _i_ = hash_function(elem);\ | |
| _i_ %= (dim);\ | |
| while ((_e_=(table)[_i_])!=NULL && comparator(_e_, (elem))!=0 && _count_<(dim)) {\ | |
| _count_ ++;\ | |
| _i_ = (_i_ + SGLIB_HASH_TAB_SHIFT_CONSTANT) % (dim);\ | |
| }\ | |
| (resultIndex) = _i_;\ | |
| if (_count_ < (dim)) (resultMember) = _e_;\ | |
| else (resultMember) = NULL;\ | |
| } | |
| #define SGLIB_HASH_TAB_IS_MEMBER(type, table, dim, elem, hash_function, resultIndex) {\ | |
| unsigned _i_;\ | |
| int _c_;\ | |
| type *_e_;\ | |
| _count = 0;\ | |
| _i_ = hash_function(elem);\ | |
| _i_ %= (dim);\ | |
| while ((_e_=(table)[_i_])!=NULL && _e_!=(elem) && _c_<(dim)) {\ | |
| _c_ ++;\ | |
| _i_ = (_i_ + SGLIB_HASH_TAB_SHIFT_CONSTANT) % (dim);\ | |
| }\ | |
| if (_e_==(elem)) (resultIndex) = _i_;\ | |
| else (resultIndex) = -1;\ | |
| } | |
| #define SGLIB_HASH_TAB_MAP_ON_ELEMENTS(type, table, dim, iteratedIndex, iteratedVariable, command) {\ | |
| unsigned iteratedIndex;\ | |
| type *iteratedVariable;\ | |
| for(iteratedIndex=0; iteratedIndex < (dim); iteratedIndex++) {\ | |
| iteratedVariable = (table)[iteratedIndex];\ | |
| if (iteratedVariable != NULL) {command;}\ | |
| }\ | |
| } | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ------------------------------------ lists (level 0) --------------------- */ | |
| #define SGLIB_LIST_ADD(type, list, elem, next) {\ | |
| (elem)->next = (list);\ | |
| (list) = (elem);\ | |
| } | |
| #define SGLIB_LIST_CONCAT(type, first, second, next) {\ | |
| if ((first)==NULL) {\ | |
| (first) = (second);\ | |
| } else {\ | |
| type *_p_;\ | |
| for(_p_ = (first); _p_->next!=NULL; _p_=_p_->next) ;\ | |
| _p_->next = (second);\ | |
| }\ | |
| } | |
| #define SGLIB_LIST_DELETE(type, list, elem, next) {\ | |
| type **_p_;\ | |
| for(_p_ = &(list); *_p_!=NULL && *_p_!=(elem); _p_= &(*_p_)->next) ;\ | |
| assert(*_p_!=NULL && "element is not member of the container, use DELETE_IF_MEMBER instead"!=NULL);\ | |
| *_p_ = (*_p_)->next;\ | |
| } | |
| #define SGLIB_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, next, member) {\ | |
| type *_p_;\ | |
| for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) != 0; _p_= _p_->next) ;\ | |
| (member) = _p_;\ | |
| if (_p_ == NULL) {\ | |
| SGLIB_LIST_ADD(type, list, elem, next);\ | |
| }\ | |
| } | |
| #define SGLIB_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, next, member) {\ | |
| type **_p_;\ | |
| for(_p_ = &(list); *_p_!=NULL && comparator((*_p_), (elem)) != 0; _p_= &(*_p_)->next) ;\ | |
| (member) = *_p_;\ | |
| if (*_p_ != NULL) {\ | |
| *_p_ = (*_p_)->next;\ | |
| }\ | |
| } | |
| #define SGLIB_LIST_IS_MEMBER(type, list, elem, next, result) {\ | |
| type *_p_;\ | |
| for(_p_ = (list); _p_!=NULL && _p_ != (elem); _p_= _p_->next) ;\ | |
| (result) = (_p_!=NULL);\ | |
| } | |
| #define SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, next, member) {\ | |
| type *_p_;\ | |
| for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) != 0; _p_= _p_->next) ;\ | |
| (member) = _p_;\ | |
| } | |
| #define SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command) {\ | |
| type *_ne_;\ | |
| type *iteratedVariable;\ | |
| (iteratedVariable) = (list);\ | |
| while ((iteratedVariable)!=NULL) {\ | |
| _ne_ = (iteratedVariable)->next;\ | |
| {command;};\ | |
| (iteratedVariable) = _ne_;\ | |
| }\ | |
| } | |
| #define SGLIB_LIST_LEN(type, list, next, result) {\ | |
| type *_ce_;\ | |
| (void)(_ce_);\ | |
| (result) = 0;\ | |
| SGLIB_LIST_MAP_ON_ELEMENTS(type, list, _ce_, next, (result)++);\ | |
| } | |
| #define SGLIB_LIST_REVERSE(type, list, next) {\ | |
| type *_list_,*_tmp_,*_res_;\ | |
| _list_ = (list);\ | |
| _res_ = NULL;\ | |
| while (_list_!=NULL) {\ | |
| _tmp_ = _list_->next; _list_->next = _res_;\ | |
| _res_ = _list_; _list_ = _tmp_;\ | |
| }\ | |
| (list) = _res_;\ | |
| } | |
| #define SGLIB_LIST_SORT(type, list, comparator, next) {\ | |
| /* a non-recursive merge sort on lists */\ | |
| type *_r_;\ | |
| type *_a_, *_b_, *_todo_, *_t_, **_restail_;\ | |
| int _i_, _n_, _contFlag_;\ | |
| _r_ = (list);\ | |
| _contFlag_ = 1;\ | |
| for(_n_ = 1; _contFlag_; _n_ = _n_+_n_) {\ | |
| _todo_ = _r_; _r_ = NULL; _restail_ = &_r_; _contFlag_ =0;\ | |
| while (_todo_!=NULL) {\ | |
| _a_ = _todo_;\ | |
| for(_i_ = 1, _t_ = _a_; _i_ < _n_ && _t_!=NULL; _i_++, _t_ = _t_->next) ;\ | |
| if (_t_ ==NULL) {\ | |
| *_restail_ = _a_;\ | |
| break;\ | |
| }\ | |
| _b_ = _t_->next; _t_->next=NULL;\ | |
| for(_i_ =1, _t_ = _b_; _i_<_n_ && _t_!=NULL; _i_++, _t_ = _t_->next) ;\ | |
| if (_t_ ==NULL) {\ | |
| _todo_ =NULL;\ | |
| } else {\ | |
| _todo_ = _t_->next; _t_->next=NULL;\ | |
| }\ | |
| /* merge */\ | |
| while (_a_!=NULL && _b_!=NULL) {\ | |
| if (comparator(_a_, _b_) < 0) {\ | |
| *_restail_ = _a_; _restail_ = &(_a_->next); _a_ = _a_->next;\ | |
| } else {\ | |
| *_restail_ = _b_; _restail_ = &(_b_->next); _b_ = _b_->next;\ | |
| }\ | |
| }\ | |
| if (_a_!=NULL) *_restail_ = _a_;\ | |
| else *_restail_ = _b_;\ | |
| while (*_restail_!=NULL) _restail_ = &((*_restail_)->next);\ | |
| _contFlag_ =1;\ | |
| }\ | |
| }\ | |
| (list) = _r_;\ | |
| } | |
| /* --------------------------------- sorted list (level 0) --------------------- */ | |
| /* | |
| All operations suppose that the list is sorted and they preserve | |
| this property. | |
| */ | |
| #define SGLIB_SORTED_LIST_ADD(type, list, elem, comparator, next) {\ | |
| type **_e_;\ | |
| int _cmpres_;\ | |
| SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmpres_, _e_);\ | |
| (elem)->next = *_e_;\ | |
| *_e_ = (elem);\ | |
| } | |
| #define SGLIB_SORTED_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, next, member) {\ | |
| type **_e_;\ | |
| int _cmp_res_;\ | |
| SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmp_res_, _e_);\ | |
| if (_cmp_res_ != 0) {\ | |
| (elem)->next = *_e_;\ | |
| *_e_ = (elem);\ | |
| (member) = NULL;\ | |
| } else {\ | |
| (member) = *_e_;\ | |
| }\ | |
| } | |
| #define SGLIB_SORTED_LIST_DELETE(type, list, elem, next) {\ | |
| SGLIB_LIST_DELETE(type, list, elem, next);\ | |
| } | |
| #define SGLIB_SORTED_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, next, member) {\ | |
| type **_e_;\ | |
| int _cmp_res_;\ | |
| SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, _cmp_res_, _e_);\ | |
| if (_cmp_res_ == 0) {\ | |
| (member) = *_e_;\ | |
| *_e_ = (*_e_)->next;\ | |
| } else {\ | |
| (member) = NULL;\ | |
| }\ | |
| } | |
| #define SGLIB_SORTED_LIST_FIND_MEMBER(type, list, elem, comparator, next, member) {\ | |
| type *_p_;\ | |
| int _cmpres_ = 1;\ | |
| for(_p_ = (list); _p_!=NULL && (_cmpres_=comparator(_p_, (elem))) < 0; _p_=_p_->next) ;\ | |
| if (_cmpres_ != 0) (member) = NULL;\ | |
| else (member) = _p_;\ | |
| } | |
| #define SGLIB_SORTED_LIST_IS_MEMBER(type, list, elem, comparator, next, result) {\ | |
| type *_p_;\ | |
| for(_p_ = (list); _p_!=NULL && comparator(_p_, (elem)) < 0; _p_=_p_->next) ;\ | |
| while (_p_ != NULL && _p_ != (elem) && comparator(_p_, (elem)) == 0) _p_=_p_->next;\ | |
| (result) = (_p_ == (elem));\ | |
| } | |
| #define SGLIB_SORTED_LIST_FIND_MEMBER_OR_PLACE(type, list, elem, comparator, next, comparator_result, member_ptr) {\ | |
| (comparator_result) = -1;\ | |
| for((member_ptr) = &(list);\ | |
| *(member_ptr)!=NULL && ((comparator_result)=comparator((*member_ptr), (elem))) < 0;\ | |
| (member_ptr) = &(*(member_ptr))->next) ;\ | |
| } | |
| #define SGLIB_SORTED_LIST_LEN(type, list, next, result) {\ | |
| SGLIB_LIST_LEN(type, list, next, result);\ | |
| } | |
| #define SGLIB_SORTED_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command) {\ | |
| SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, next, command);\ | |
| } | |
| /* ------------------------------- double linked list (level 0) ------------------------- */ | |
| /* | |
| Lists with back pointer to previous element. Those lists implements deletion | |
| of an element in a constant time. | |
| */ | |
| #define SGLIB___DL_LIST_CREATE_SINGLETON(type, list, elem, previous, next) {\ | |
| (list) = (elem);\ | |
| (list)->next = (list)->previous = NULL;\ | |
| } | |
| #define SGLIB_DL_LIST_ADD_AFTER(type, place, elem, previous, next) {\ | |
| if ((place) == NULL) {\ | |
| SGLIB___DL_LIST_CREATE_SINGLETON(type, place, elem, previous, next);\ | |
| } else {\ | |
| (elem)->next = (place)->next;\ | |
| (elem)->previous = (place);\ | |
| (place)->next = (elem);\ | |
| if ((elem)->next != NULL) (elem)->next->previous = (elem);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_ADD_BEFORE(type, place, elem, previous, next) {\ | |
| if ((place) == NULL) {\ | |
| SGLIB___DL_LIST_CREATE_SINGLETON(type, place, elem, previous, next);\ | |
| } else {\ | |
| (elem)->next = (place);\ | |
| (elem)->previous = (place)->previous;\ | |
| (place)->previous = (elem);\ | |
| if ((elem)->previous != NULL) (elem)->previous->next = (elem);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_ADD(type, list, elem, previous, next) {\ | |
| SGLIB_DL_LIST_ADD_BEFORE(type, list, elem, previous, next)\ | |
| (list) = (elem);\ | |
| } | |
| #define SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, the_add_operation) {\ | |
| type *_dlp_;\ | |
| for(_dlp_ = (list); _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->previous) ;\ | |
| if (_dlp_ == NULL && (list) != NULL) {\ | |
| for(_dlp_ = (list)->next; _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->next) ;\ | |
| }\ | |
| (member) = _dlp_;\ | |
| if (_dlp_ == NULL) {\ | |
| the_add_operation(type, list, elem, previous, next);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_ADD_BEFORE_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\ | |
| SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD_BEFORE);\ | |
| } | |
| #define SGLIB_DL_LIST_ADD_AFTER_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\ | |
| SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD_AFTER);\ | |
| } | |
| #define SGLIB_DL_LIST_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member) {\ | |
| SGLIB___DL_LIST_GENERIC_ADD_IF_NOT_MEMBER(type, list, elem, comparator, previous, next, member, SGLIB_DL_LIST_ADD);\ | |
| } | |
| #define SGLIB_DL_LIST_CONCAT(type, first, second, previous, next) {\ | |
| if ((first)==NULL) {\ | |
| (first) = (second);\ | |
| } else if ((second)!=NULL) {\ | |
| type *_dlp_;\ | |
| for(_dlp_ = (first); _dlp_->next!=NULL; _dlp_=_dlp_->next) { };\ | |
| SGLIB_DL_LIST_ADD_AFTER(type, _dlp_, second, previous, next);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_DELETE(type, list, elem, previous, next) {\ | |
| type *_l_;\ | |
| _l_ = (list);\ | |
| if (_l_ == (elem)) {\ | |
| if ((elem)->previous != NULL) _l_ = (elem)->previous;\ | |
| else _l_ = (elem)->next;\ | |
| }\ | |
| if ((elem)->next != NULL) (elem)->next->previous = (elem)->previous;\ | |
| if ((elem)->previous != NULL) (elem)->previous->next = (elem)->next;\ | |
| (list) = _l_;\ | |
| } | |
| #define SGLIB_DL_LIST_DELETE_IF_MEMBER(type, list, elem, comparator, previous, next, member) {\ | |
| type *_dlp_;\ | |
| for(_dlp_ = (list); _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->previous) ;\ | |
| if (_dlp_ == NULL && (list) != NULL) {\ | |
| for(_dlp_ = (list)->next; _dlp_!=NULL && comparator(_dlp_, (elem)) != 0; _dlp_= _dlp_->next) ;\ | |
| }\ | |
| (member) = _dlp_;\ | |
| if (_dlp_ != NULL) {\ | |
| SGLIB_DL_LIST_DELETE(type, list, _dlp_, previous, next);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_IS_MEMBER(type, list, elem, previous, next, result) {\ | |
| type *_dlp_;\ | |
| SGLIB_LIST_IS_MEMBER(type, list, elem, previous, result);\ | |
| if (result == 0 && (list) != NULL) {\ | |
| _dlp_ = (list)->next;\ | |
| SGLIB_LIST_IS_MEMBER(type, _dlp_, elem, next, result);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_FIND_MEMBER(type, list, elem, comparator, previous, next, member) {\ | |
| type *_dlp_;\ | |
| SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, previous, member);\ | |
| if ((member) == NULL && (list) != NULL) {\ | |
| _dlp_ = (list)->next;\ | |
| SGLIB_LIST_FIND_MEMBER(type, _dlp_, elem, comparator, next, member);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, previous, next, command) {\ | |
| type *_dl_;\ | |
| type *iteratedVariable;\ | |
| (void)(iteratedVariable);\ | |
| if ((list)!=NULL) {\ | |
| _dl_ = (list)->next;\ | |
| SGLIB_LIST_MAP_ON_ELEMENTS(type, list, iteratedVariable, previous, command);\ | |
| SGLIB_LIST_MAP_ON_ELEMENTS(type, _dl_, iteratedVariable, next, command);\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_SORT(type, list, comparator, previous, next) {\ | |
| type *_dll_;\ | |
| _dll_ = (list);\ | |
| if (_dll_ != NULL) {\ | |
| for(; _dll_->previous!=NULL; _dll_=_dll_->previous) { };\ | |
| SGLIB_LIST_SORT(type, _dll_, comparator, next);\ | |
| SGLIB___DL_LIST_CREATE_FROM_LIST(type, _dll_, previous, next);\ | |
| (list) = _dll_;\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_GET_FIRST(type, list, previous, next, result) {\ | |
| type *_dll_;\ | |
| _dll_ = (list);\ | |
| if (_dll_ != NULL) {\ | |
| for(; _dll_->previous!=NULL; _dll_=_dll_->previous) ;\ | |
| }\ | |
| (result) = _dll_;\ | |
| } | |
| #define SGLIB_DL_LIST_GET_LAST(type, list, previous, next, result) {\ | |
| type *_dll_;\ | |
| _dll_ = (list);\ | |
| if (_dll_ != NULL) {\ | |
| for(; _dll_->next!=NULL; _dll_=_dll_->next) ;\ | |
| }\ | |
| (result) = _dll_;\ | |
| } | |
| #define SGLIB_DL_LIST_LEN(type, list, previous, next, result) {\ | |
| type *_dl_;\ | |
| int _r1_, _r2_;\ | |
| if ((list)==NULL) {\ | |
| (result) = 0;\ | |
| } else {\ | |
| SGLIB_LIST_LEN(type, list, previous, _r1_);\ | |
| _dl_ = (list)->next;\ | |
| SGLIB_LIST_LEN(type, _dl_, next, _r2_);\ | |
| (result) = _r1_ + _r2_;\ | |
| }\ | |
| } | |
| #define SGLIB_DL_LIST_REVERSE(type, list, previous, next) {\ | |
| type *_list_,*_nlist_,*_dlp_,*_dln_;\ | |
| _list_ = (list);\ | |
| if (_list_!=NULL) {\ | |
| _nlist_ = _list_->next;\ | |
| while (_list_!=NULL) {\ | |
| _dln_ = _list_->next;\ | |
| _dlp_ = _list_->previous;\ | |
| _list_->next = _dlp_;\ | |
| _list_->previous = _dln_;\ | |
| _list_ = _dlp_;\ | |
| }\ | |
| while (_nlist_!=NULL) {\ | |
| _dln_ = _nlist_->next;\ | |
| _dlp_ = _nlist_->previous;\ | |
| _nlist_->next = _dlp_;\ | |
| _nlist_->previous = _dln_;\ | |
| _nlist_ = _dln_;\ | |
| }\ | |
| }\ | |
| } | |
| #define SGLIB___DL_LIST_CREATE_FROM_LIST(type, list, previous, next) {\ | |
| type *_dlp_, *_dlt_;\ | |
| _dlp_ = NULL;\ | |
| for(_dlt_ = (list); _dlt_!=NULL; _dlt_ = _dlt_->next) {\ | |
| _dlt_->previous = _dlp_;\ | |
| _dlp_ = _dlt_;\ | |
| }\ | |
| } | |
| /* ------------------------------- binary tree traversal (level 0) -------------------- */ | |
| #define SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, iteratedVariable, order, left, right, command) {\ | |
| /* this is non-recursive implementation of tree traversal */\ | |
| /* it maintains the path to the current node in the array '_path_' */\ | |
| /* the _path_[0] contains the root of the tree; */\ | |
| /* the _path_[_pathi_] contains the _current_element_ */\ | |
| /* the macro does not use the _current_element_ after execution of command */\ | |
| /* command can destroy it, it can free the element for example */\ | |
| type *_path_[SGLIB_MAX_TREE_DEEP];\ | |
| type *_right_[SGLIB_MAX_TREE_DEEP];\ | |
| char _pass_[SGLIB_MAX_TREE_DEEP];\ | |
| type *_cn_;\ | |
| int _pathi_;\ | |
| type *iteratedVariable;\ | |
| (void)(iteratedVariable);\ | |
| _cn_ = (tree);\ | |
| _pathi_ = 0;\ | |
| while (_cn_!=NULL) {\ | |
| /* push down to leftmost innermost element */\ | |
| while(_cn_!=NULL) {\ | |
| _path_[_pathi_] = _cn_;\ | |
| _right_[_pathi_] = _cn_->right;\ | |
| _pass_[_pathi_] = 0;\ | |
| _cn_ = _cn_->left;\ | |
| if (order == 0) {\ | |
| iteratedVariable = _path_[_pathi_];\ | |
| {command;}\ | |
| }\ | |
| _pathi_ ++;\ | |
| if (_pathi_ >= SGLIB_MAX_TREE_DEEP) assert(0 && "the binary_tree is too deep");\ | |
| }\ | |
| do {\ | |
| _pathi_ --;\ | |
| if ((order==1 && _pass_[_pathi_] == 0)\ | |
| || (order == 2 && (_pass_[_pathi_] == 1 || _right_[_pathi_]==NULL))) {\ | |
| iteratedVariable = _path_[_pathi_];\ | |
| {command;}\ | |
| }\ | |
| _pass_[_pathi_] ++;\ | |
| } while (_pathi_>0 && _right_[_pathi_]==NULL) ;\ | |
| _cn_ = _right_[_pathi_];\ | |
| _right_[_pathi_] = NULL;\ | |
| _pathi_ ++;\ | |
| }\ | |
| } | |
| #define SGLIB_BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, left, right, command) {\ | |
| SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 1, left, right, command);\ | |
| } | |
| #define SGLIB_BIN_TREE_MAP_ON_ELEMENTS_PREORDER(type, tree, _current_element_, left, right, command) {\ | |
| SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 0, left, right, command);\ | |
| } | |
| #define SGLIB_BIN_TREE_MAP_ON_ELEMENTS_POSTORDER(type, tree, _current_element_, left, right, command) {\ | |
| SGLIB___BIN_TREE_MAP_ON_ELEMENTS(type, tree, _current_element_, 2, left, right, command);\ | |
| } | |
| #define SGLIB___BIN_TREE_FIND_MEMBER(type, tree, elem, left, right, comparator, res) {\ | |
| type *_s_;\ | |
| int _c_;\ | |
| _s_ = (tree);\ | |
| while (_s_!=NULL) {\ | |
| _c_ = comparator((elem), _s_);\ | |
| if (_c_ < 0) _s_ = _s_->left;\ | |
| else if (_c_ > 0) _s_ = _s_->right;\ | |
| else break;\ | |
| }\ | |
| (res) = _s_;\ | |
| } | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* - LEVEL - 1 INTERFACE - */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ------------------------------ STATIC ARRAYS ------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ----------------------------- array sorting (level 1) ---------------------- */ | |
| #define SGLIB_DEFINE_ARRAY_SORTING_PROTOTYPES(type, comparator) \ | |
| extern void sglib_##type##_array_quick_sort(type *a, int max);\ | |
| extern void sglib_##type##_array_heap_sort(type *a, int max);\ | |
| #define SGLIB_DEFINE_ARRAY_SORTING_FUNCTIONS(type, comparator) \ | |
| void sglib_##type##_array_quick_sort(type *a, int max) {\ | |
| SGLIB_ARRAY_SINGLE_QUICK_SORT(type, a, max, comparator);\ | |
| }\ | |
| void sglib_##type##_array_heap_sort(type *a, int max) {\ | |
| SGLIB_ARRAY_SINGLE_HEAP_SORT(type, a, max, comparator);\ | |
| }\ | |
| /* ----------------------------- array queue (level 1) ------------------- */ | |
| /* sglib's queue is stored in a fixed sized array */ | |
| /* queue_type MUST be a structure containing fields: */ | |
| /* afield is the array storing elem_type */ | |
| /* ifield is the index of the first element in the queue */ | |
| /* jfield is the index of the first free element after the queue */ | |
| /* dim is the size of the array afield */ | |
| /* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ | |
| #define SGLIB_DEFINE_QUEUE_PROTOTYPES(queue_type, elem_type, afield, ifield, jfield, dim) \ | |
| extern void sglib_##queue_type##_init(queue_type *q);\ | |
| extern int sglib_##queue_type##_is_empty(queue_type *q);\ | |
| extern int sglib_##queue_type##_is_full(queue_type *q);\ | |
| extern elem_type sglib_##queue_type##_first_element(queue_type *q);\ | |
| extern elem_type *sglib_##queue_type##_first_element_ptr(queue_type *q);\ | |
| extern void sglib_##queue_type##_add_next(queue_type *q);\ | |
| extern void sglib_##queue_type##_add(queue_type *q, elem_type elem);\ | |
| extern void sglib_##queue_type##_delete_first(queue_type *q);\ | |
| extern void sglib_##queue_type##_delete(queue_type *q); | |
| #define SGLIB_DEFINE_QUEUE_FUNCTIONS(queue_type, elem_type, afield, ifield, jfield, dim) \ | |
| void sglib_##queue_type##_init(queue_type *q) {\ | |
| SGLIB_QUEUE_INIT(elem_type, q->afield, q->ifield, q->jfield);\ | |
| }\ | |
| int sglib_##queue_type##_is_empty(queue_type *q) {\ | |
| return(SGLIB_QUEUE_IS_EMPTY(elem_type, q->afield, q->ifield, q->jfield));\ | |
| }\ | |
| int sglib_##queue_type##_is_full(queue_type *q) {\ | |
| return(SGLIB_QUEUE_IS_FULL(elem_type, q->afield, q->ifield, q->jfield));\ | |
| }\ | |
| elem_type sglib_##queue_type##_first_element(queue_type *q) {\ | |
| return(SGLIB_QUEUE_FIRST_ELEMENT(elem_type, q->afield, q->ifield, q->jfield));\ | |
| }\ | |
| elem_type *sglib_##queue_type##_first_element_ptr(queue_type *q) {\ | |
| return(& SGLIB_QUEUE_FIRST_ELEMENT(elem_type, q->afield, q->ifield, q->jfield));\ | |
| }\ | |
| void sglib_##queue_type##_add_next(queue_type *q) {\ | |
| SGLIB_QUEUE_ADD_NEXT(elem_type, q->afield, q->ifield, q->jfield, dim);\ | |
| }\ | |
| void sglib_##queue_type##_add(queue_type *q, elem_type elem) {\ | |
| SGLIB_QUEUE_ADD(elem_type, q->afield, elem, q->ifield, q->jfield, dim);\ | |
| }\ | |
| void sglib_##queue_type##_delete_first(queue_type *q) {\ | |
| SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\ | |
| }\ | |
| void sglib_##queue_type##_delete(queue_type *q) {\ | |
| SGLIB_QUEUE_DELETE_FIRST(elem_type, q->afield, q->ifield, q->jfield, dim);\ | |
| } | |
| /* ------------------------ array heap (level 1) ------------------------- */ | |
| /* sglib's heap is a priority queue implemented in a fixed sized array */ | |
| /* heap_type MUST be a structure containing fields: */ | |
| /* afield is the array of size dim storing elem_type */ | |
| /* ifield is the index of the first free element after the queue */ | |
| /* !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! */ | |
| #define SGLIB_DEFINE_HEAP_PROTOTYPES(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \ | |
| extern void sglib_##heap_type##_init(heap_type *q);\ | |
| extern int sglib_##heap_type##_is_empty(heap_type *q);\ | |
| extern int sglib_##heap_type##_is_full(heap_type *q);\ | |
| extern elem_type sglib_##heap_type##_first_element(heap_type *q);\ | |
| extern elem_type *sglib_##heap_type##_first_element_ptr(heap_type *q);\ | |
| extern void sglib_##heap_type##_add_next(heap_type *q);\ | |
| extern void sglib_##heap_type##_add(heap_type *q, elem_type elem);\ | |
| extern void sglib_##heap_type##_delete_first(heap_type *q);\ | |
| extern void sglib_##heap_type##_delete(heap_type *q) | |
| #define SGLIB_DEFINE_HEAP_FUNCTIONS(heap_type, elem_type, afield, ifield, dim, comparator, elem_exchanger) \ | |
| void sglib_##heap_type##_init(heap_type *q) {\ | |
| SGLIB_HEAP_INIT(elem_type, q->afield, q->ifield);\ | |
| }\ | |
| int sglib_##heap_type##_is_empty(heap_type *q) {\ | |
| return(SGLIB_HEAP_IS_EMPTY(elem_type, q->afield, q->ifield));\ | |
| }\ | |
| int sglib_##heap_type##_is_full(heap_type *q) {\ | |
| return(SGLIB_HEAP_IS_FULL(elem_type, q->afield, q->ifield));\ | |
| }\ | |
| elem_type sglib_##heap_type##_first_element(heap_type *q) {\ | |
| return(SGLIB_HEAP_FIRST_ELEMENT(elem_type, q->afield, q->ifield));\ | |
| }\ | |
| elem_type *sglib_##heap_type##_first_element_ptr(heap_type *q) {\ | |
| return(& SGLIB_HEAP_FIRST_ELEMENT(elem_type, q->afield, q->ifield));\ | |
| }\ | |
| void sglib_##heap_type##_add_next(heap_type *q) {\ | |
| SGLIB_HEAP_ADD_NEXT(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ | |
| }\ | |
| void sglib_##heap_type##_add(heap_type *q, elem_type elem) {\ | |
| SGLIB_HEAP_ADD(elem_type, q->afield, elem, q->ifield, dim, comparator, elem_exchanger);\ | |
| }\ | |
| void sglib_##heap_type##_delete_first(heap_type *q) {\ | |
| SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ | |
| }\ | |
| void sglib_##heap_type##_delete(heap_type *q) {\ | |
| SGLIB_HEAP_DELETE_FIRST(elem_type, q->afield, q->ifield, dim, comparator, elem_exchanger);\ | |
| } | |
| /* ------------------------ hashed table (level 1) ------------------------- */ | |
| /* | |
| sglib's hash table is an array storing directly pointers to objects (not containers). | |
| In this table there is a one-to-one mapping between 'objects' stored | |
| in the table and indexes where they are placed. Each index is | |
| pointing to exactly one 'object' and each 'object' stored in the | |
| table occurs on exactly one index. Once an object is stored in the | |
| table, it can be represented via its index. | |
| type - is the type of elements | |
| dim - is the size of the hash array | |
| hash_function - is a hashing function mapping type* to unsigned | |
| comparator - is a comparator on elements | |
| !!!!!!! This data structure is NOT documented, do not use it !!!!!!!!!! | |
| */ | |
| #define SGLIB_DEFINE_HASHED_TABLE_PROTOTYPES(type, dim, hash_function, comparator) \ | |
| struct sglib_hashed_##type##_iterator {\ | |
| int currentIndex;\ | |
| int (*subcomparator)(type *, type *);\ | |
| type *equalto;\ | |
| };\ | |
| extern void sglib_hashed_##type##_init(type *table[dim]);\ | |
| extern int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member);\ | |
| extern int sglib_hashed_##type##_is_member(type *table[dim], type *elem);\ | |
| extern type * sglib_hashed_##type##_find_member(type *table[dim], type *elem);\ | |
| extern type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]);\ | |
| extern type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto);\ | |
| extern type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it);\ | |
| extern type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it); | |
| #define SGLIB_DEFINE_HASHED_TABLE_FUNCTIONS(type, dim, hash_function, comparator) \ | |
| struct sglib_hashed_##type##_iterator {\ | |
| int currentIndex;\ | |
| type **table;\ | |
| int (*subcomparator)(type *, type *);\ | |
| type *equalto;\ | |
| };\ | |
| void sglib_hashed_##type##_init(type *table[dim]) {\ | |
| SGLIB_HASH_TAB_INIT(type, table, dim);\ | |
| }\ | |
| int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member) {\ | |
| SGLIB_HASH_TAB_ADD_IF_NOT_MEMBER(type, table, dim, elem, hash_function, comparator, *member);\ | |
| }\ | |
| int sglib_hashed_##type##_is_member(type *table[dim], type *elem) {\ | |
| int ind;\ | |
| SGLIB_HASH_TAB_IS_MEMBER(type, table, dim, elem, hash_function, ind);\ | |
| return(ind != -1);\ | |
| }\ | |
| type * sglib_hashed_##type##_find_member(type *table[dim], type *elem) {\ | |
| type *mmb;\ | |
| int ind;\ | |
| SGLIB_HASH_TAB_FIND_MEMBER(type, table, dim, elem, hash_function, comparator, ind, mmb);\ | |
| return(mmb);\ | |
| }\ | |
| type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto) {\ | |
| int i;\ | |
| it->table = table;\ | |
| it->subcomparator = subcomparator;\ | |
| it->equalto = equalto;\ | |
| for(i=0; i<(dim) && table[i]==NULL; i++) ;\ | |
| it->currentIndex = i;\ | |
| if (i<(dim)) return(table[i]);\ | |
| return(NULL);\ | |
| }\ | |
| type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]) {\ | |
| sglib_hashed_##type##_it_init_on_equal(it, table, NULL, NULL);\ | |
| }\ | |
| type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it) {\ | |
| return(table[it->currentIndex]);\ | |
| }\ | |
| type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it) {\ | |
| i=it->currentIndex;\ | |
| if (i<(dim)) {\ | |
| for(i++; i<(dim) && table[i]==NULL; i++) ;\ | |
| }\ | |
| it->currentIndex = i;\ | |
| if (i<(dim)) return(table[i]);\ | |
| return(NULL);\ | |
| } | |
| /* ------------------- hashed container (only for level 1) -------------------- */ | |
| /* | |
| hashed container is a table of given fixed size containing another | |
| (dynamic) base container in each cell. Once an object should be | |
| inserted into the hashed container, a hash function is used to | |
| determine the cell where the object belongs and the object is | |
| inserted into the base container stored in this cell. Usually the | |
| base container is simply a list or a sorted list, but it can be a | |
| red-black tree as well. | |
| parameters: | |
| type - the type of the container stored in each cell. | |
| dim - the size of the hashed array | |
| hash_function - the hashing function hashing 'type *' to unsigned. | |
| */ | |
| #define SGLIB_DEFINE_HASHED_CONTAINER_PROTOTYPES(type, dim, hash_function) \ | |
| struct sglib_hashed_##type##_iterator {\ | |
| struct sglib_##type##_iterator containerIt;\ | |
| type **table;\ | |
| int currentIndex;\ | |
| int (*subcomparator)(type *, type *);\ | |
| type *equalto;\ | |
| };\ | |
| extern void sglib_hashed_##type##_init(type *table[dim]);\ | |
| extern void sglib_hashed_##type##_add(type *table[dim], type *elem);\ | |
| extern int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member);\ | |
| extern void sglib_hashed_##type##_delete(type *table[dim], type *elem);\ | |
| extern int sglib_hashed_##type##_delete_if_member(type *table[dim], type *elem, type **memb);\ | |
| extern int sglib_hashed_##type##_is_member(type *table[dim], type *elem);\ | |
| extern type * sglib_hashed_##type##_find_member(type *table[dim], type *elem);\ | |
| extern type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]);\ | |
| extern type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto);\ | |
| extern type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it);\ | |
| extern type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it); | |
| #define SGLIB_DEFINE_HASHED_CONTAINER_FUNCTIONS(type, dim, hash_function) \ | |
| /*extern unsigned hash_function(type *elem);*/\ | |
| void sglib_hashed_##type##_init(type *table[dim]) {\ | |
| unsigned i;\ | |
| for(i=0; i<(dim); i++) table[i] = NULL;\ | |
| }\ | |
| void sglib_hashed_##type##_add(type *table[dim], type *elem) {\ | |
| unsigned i;\ | |
| i = ((unsigned)hash_function(elem)) % (dim);\ | |
| sglib_##type##_add(&(table)[i], elem);\ | |
| }\ | |
| int sglib_hashed_##type##_add_if_not_member(type *table[dim], type *elem, type **member) {\ | |
| unsigned i;\ | |
| i = ((unsigned)hash_function(elem)) % (dim);\ | |
| return(sglib_##type##_add_if_not_member(&(table)[i], elem, member));\ | |
| }\ | |
| void sglib_hashed_##type##_delete(type *table[dim], type *elem) {\ | |
| unsigned i;\ | |
| i = ((unsigned)hash_function(elem)) % (dim);\ | |
| sglib_##type##_delete(&(table)[i], elem);\ | |
| }\ | |
| int sglib_hashed_##type##_delete_if_member(type *table[dim], type *elem, type **memb) {\ | |
| unsigned i;\ | |
| i = ((unsigned)hash_function(elem)) % (dim);\ | |
| return(sglib_##type##_delete_if_member(&(table)[i], elem, memb));\ | |
| }\ | |
| int sglib_hashed_##type##_is_member(type *table[dim], type *elem) {\ | |
| unsigned i;\ | |
| i = ((unsigned)hash_function(elem)) % (dim);\ | |
| return(sglib_##type##_is_member((table)[i], elem));\ | |
| }\ | |
| type * sglib_hashed_##type##_find_member(type *table[dim], type *elem) {\ | |
| unsigned i;\ | |
| i = ((unsigned)hash_function(elem)) % (dim);\ | |
| return(sglib_##type##_find_member((table)[i], elem));\ | |
| }\ | |
| type *sglib_hashed_##type##_it_init_on_equal(struct sglib_hashed_##type##_iterator *it, type *table[dim], int (*subcomparator)(type *, type *), type *equalto) {\ | |
| type *e;\ | |
| it->table = table;\ | |
| it->currentIndex = 0;\ | |
| it->subcomparator = subcomparator;\ | |
| it->equalto = equalto;\ | |
| e = sglib_##type##_it_init_on_equal(&it->containerIt, table[it->currentIndex], it->subcomparator, it->equalto);\ | |
| if (e==NULL) e = sglib_hashed_##type##_it_next(it);\ | |
| return(e);\ | |
| }\ | |
| type *sglib_hashed_##type##_it_init(struct sglib_hashed_##type##_iterator *it, type *table[dim]) {\ | |
| return(sglib_hashed_##type##_it_init_on_equal(it, table, NULL, NULL));\ | |
| }\ | |
| type *sglib_hashed_##type##_it_current(struct sglib_hashed_##type##_iterator *it) {\ | |
| return(sglib_##type##_it_current(&it->containerIt));\ | |
| }\ | |
| type *sglib_hashed_##type##_it_next(struct sglib_hashed_##type##_iterator *it) {\ | |
| type *e;\ | |
| e = sglib_##type##_it_next(&it->containerIt);\ | |
| while (e==NULL && (++(it->currentIndex))<(dim)) {\ | |
| e = sglib_##type##_it_init_on_equal(&it->containerIt, it->table[it->currentIndex], it->subcomparator, it->equalto);\ | |
| }\ | |
| return(e);\ | |
| } | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ------------------------- DYNAMIC DATA STRUCTURES -------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ------------------------------------ list (level 1) -------------------------------- */ | |
| #define SGLIB_DEFINE_LIST_PROTOTYPES(type, comparator, next) \ | |
| struct sglib_##type##_iterator {\ | |
| type *currentelem;\ | |
| type *nextelem;\ | |
| int (*subcomparator)(type *, type *);\ | |
| type *equalto;\ | |
| };\ | |
| extern void sglib_##type##_add(type **list, type *elem);\ | |
| extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\ | |
| extern void sglib_##type##_concat(type **first, type *second);\ | |
| extern void sglib_##type##_delete(type **list, type *elem);\ | |
| extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\ | |
| extern int sglib_##type##_is_member(type *list, type *elem);\ | |
| extern type *sglib_##type##_find_member(type *list, type *elem);\ | |
| extern void sglib_##type##_sort(type **list);\ | |
| extern int sglib_##type##_len(type *list);\ | |
| extern void sglib_##type##_reverse(type **list);\ | |
| extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list);\ | |
| extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto);\ | |
| extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it);\ | |
| extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); | |
| #define SGLIB_DEFINE_LIST_FUNCTIONS(type, comparator, next) \ | |
| int sglib_##type##_is_member(type *list, type *elem) {\ | |
| int result;\ | |
| SGLIB_LIST_IS_MEMBER(type, list, elem, next, result);\ | |
| return(result);\ | |
| }\ | |
| type *sglib_##type##_find_member(type *list, type *elem) {\ | |
| type *result;\ | |
| SGLIB_LIST_FIND_MEMBER(type, list, elem, comparator, next, result);\ | |
| return(result);\ | |
| }\ | |
| int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\ | |
| SGLIB_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, next, *member);\ | |
| return(*member==NULL);\ | |
| }\ | |
| void sglib_##type##_add(type **list, type *elem) {\ | |
| SGLIB_LIST_ADD(type, *list, elem, next);\ | |
| }\ | |
| void sglib_##type##_concat(type **first, type *second) {\ | |
| SGLIB_LIST_CONCAT(type, *first, second, next);\ | |
| }\ | |
| void sglib_##type##_delete(type **list, type *elem) {\ | |
| SGLIB_LIST_DELETE(type, *list, elem, next);\ | |
| }\ | |
| int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\ | |
| SGLIB_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, next, *member);\ | |
| return(*member!=NULL);\ | |
| }\ | |
| void sglib_##type##_sort(type **list) {\ | |
| SGLIB_LIST_SORT(type, *list, comparator, next);\ | |
| }\ | |
| int sglib_##type##_len(type *list) {\ | |
| int res;\ | |
| SGLIB_LIST_LEN(type, list, next, res);\ | |
| return(res);\ | |
| }\ | |
| void sglib_##type##_reverse(type **list) {\ | |
| SGLIB_LIST_REVERSE(type, *list, next);\ | |
| }\ | |
| \ | |
| type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\ | |
| it->subcomparator = subcomparator;\ | |
| it->equalto = equalto;\ | |
| it->nextelem = list;\ | |
| return(sglib_##type##_it_next(it));\ | |
| }\ | |
| type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\ | |
| return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ | |
| return(it->currentelem);\ | |
| }\ | |
| type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ | |
| type *ce, *eq;\ | |
| int (*scp)(type *, type *);\ | |
| ce = it->nextelem;\ | |
| it->nextelem = NULL;\ | |
| if (it->subcomparator != NULL) {\ | |
| eq = it->equalto;\ | |
| scp = it->subcomparator;\ | |
| while (ce!=NULL && scp(ce, eq)!=0) ce = ce->next;\ | |
| }\ | |
| it->currentelem = ce;\ | |
| if (ce != NULL) it->nextelem = ce->next;\ | |
| return(ce);\ | |
| } | |
| /* ----------------------------- sorted list (level 1) ----------------------------------- */ | |
| #define SGLIB_DEFINE_SORTED_LIST_PROTOTYPES(type, comparator, next) \ | |
| struct sglib_##type##_iterator {\ | |
| type *currentelem;\ | |
| type *nextelem;\ | |
| int (*subcomparator)(type *, type *);\ | |
| type *equalto;\ | |
| };\ | |
| extern void sglib_##type##_add(type **list, type *elem);\ | |
| extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\ | |
| extern void sglib_##type##_delete(type **list, type *elem);\ | |
| extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\ | |
| extern int sglib_##type##_is_member(type *list, type *elem);\ | |
| extern type *sglib_##type##_find_member(type *list, type *elem);\ | |
| extern int sglib_##type##_len(type *list);\ | |
| extern void sglib_##type##_sort(type **list);\ | |
| extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list);\ | |
| extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto);\ | |
| extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it);\ | |
| extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); | |
| #define SGLIB_DEFINE_SORTED_LIST_FUNCTIONS(type, comparator, next) \ | |
| int sglib_##type##_is_member(type *list, type *elem) {\ | |
| int result;\ | |
| SGLIB_SORTED_LIST_IS_MEMBER(type, list, elem, comparator, next, result);\ | |
| return(result);\ | |
| }\ | |
| type *sglib_##type##_find_member(type *list, type *elem) {\ | |
| type *result;\ | |
| SGLIB_SORTED_LIST_FIND_MEMBER(type, list, elem, comparator, next, result);\ | |
| return(result);\ | |
| }\ | |
| int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\ | |
| SGLIB_SORTED_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, next, *member);\ | |
| return(*member==NULL);\ | |
| }\ | |
| void sglib_##type##_add(type **list, type *elem) {\ | |
| SGLIB_SORTED_LIST_ADD(type, *list, elem, comparator, next);\ | |
| }\ | |
| void sglib_##type##_delete(type **list, type *elem) {\ | |
| SGLIB_SORTED_LIST_DELETE(type, *list, elem, next);\ | |
| }\ | |
| int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\ | |
| SGLIB_SORTED_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, next, *member);\ | |
| return(*member!=NULL);\ | |
| }\ | |
| int sglib_##type##_len(type *list) {\ | |
| int res;\ | |
| SGLIB_SORTED_LIST_LEN(type, list, next, res);\ | |
| return(res);\ | |
| }\ | |
| void sglib_##type##_sort(type **list) {\ | |
| SGLIB_LIST_SORT(type, *list, comparator, next);\ | |
| }\ | |
| \ | |
| type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\ | |
| it->subcomparator = subcomparator;\ | |
| it->equalto = equalto;\ | |
| it->nextelem = list;\ | |
| return(sglib_##type##_it_next(it));\ | |
| }\ | |
| type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\ | |
| return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ | |
| return(it->currentelem);\ | |
| }\ | |
| type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ | |
| type *ce, *eq;\ | |
| int (*scp)(type *, type *);\ | |
| int c;\ | |
| ce = it->nextelem;\ | |
| it->nextelem = NULL;\ | |
| if (it->subcomparator != NULL) {\ | |
| eq = it->equalto;\ | |
| scp = it->subcomparator;\ | |
| while (ce!=NULL && (c=scp(ce, eq)) < 0) ce = ce->next;\ | |
| if (ce != NULL && c > 0) ce = NULL;\ | |
| }\ | |
| it->currentelem = ce;\ | |
| if (ce != NULL) it->nextelem = ce->next;\ | |
| return(ce);\ | |
| } | |
| /* ----------------------------- double linked list (level 1) ------------------------------ */ | |
| #define SGLIB_DEFINE_DL_LIST_PROTOTYPES(type, comparator, previous, next) \ | |
| struct sglib_##type##_iterator {\ | |
| type *currentelem;\ | |
| type *prevelem;\ | |
| type *nextelem;\ | |
| int (*subcomparator)(type *, type *);\ | |
| type *equalto;\ | |
| };\ | |
| extern void sglib_##type##_add(type **list, type *elem);\ | |
| extern void sglib_##type##_add_before(type **list, type *elem);\ | |
| extern void sglib_##type##_add_after(type **list, type *elem);\ | |
| extern int sglib_##type##_add_if_not_member(type **list, type *elem, type **member);\ | |
| extern int sglib_##type##_add_before_if_not_member(type **list, type *elem, type **member);\ | |
| extern int sglib_##type##_add_after_if_not_member(type **list, type *elem, type **member);\ | |
| extern void sglib_##type##_concat(type **first, type *second);\ | |
| extern void sglib_##type##_delete(type **list, type *elem);\ | |
| extern int sglib_##type##_delete_if_member(type **list, type *elem, type **member);\ | |
| extern int sglib_##type##_is_member(type *list, type *elem);\ | |
| extern type *sglib_##type##_find_member(type *list, type *elem);\ | |
| extern type *sglib_##type##_get_first(type *list);\ | |
| extern type *sglib_##type##_get_last(type *list);\ | |
| extern void sglib_##type##_sort(type **list);\ | |
| extern int sglib_##type##_len(type *list);\ | |
| extern void sglib_##type##_reverse(type **list);\ | |
| extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list);\ | |
| extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto);\ | |
| extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it);\ | |
| extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it); | |
| #define SGLIB_DEFINE_DL_LIST_FUNCTIONS(type, comparator, previous, next) \ | |
| void sglib_##type##_add(type **list, type *elem) {\ | |
| SGLIB_DL_LIST_ADD(type, *list, elem, previous, next);\ | |
| }\ | |
| void sglib_##type##_add_after(type **list, type *elem) {\ | |
| SGLIB_DL_LIST_ADD_AFTER(type, *list, elem, previous, next);\ | |
| }\ | |
| void sglib_##type##_add_before(type **list, type *elem) {\ | |
| SGLIB_DL_LIST_ADD_BEFORE(type, *list, elem, previous, next);\ | |
| }\ | |
| int sglib_##type##_add_if_not_member(type **list, type *elem, type **member) {\ | |
| SGLIB_DL_LIST_ADD_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\ | |
| return(*member==NULL);\ | |
| }\ | |
| int sglib_##type##_add_after_if_not_member(type **list, type *elem, type **member) {\ | |
| SGLIB_DL_LIST_ADD_AFTER_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\ | |
| return(*member==NULL);\ | |
| }\ | |
| int sglib_##type##_add_before_if_not_member(type **list, type *elem, type **member) {\ | |
| SGLIB_DL_LIST_ADD_BEFORE_IF_NOT_MEMBER(type, *list, elem, comparator, previous, next, *member);\ | |
| return(*member==NULL);\ | |
| }\ | |
| void sglib_##type##_concat(type **first, type *second) {\ | |
| SGLIB_DL_LIST_CONCAT(type, *first, second, previous, next);\ | |
| }\ | |
| void sglib_##type##_delete(type **list, type *elem) {\ | |
| SGLIB_DL_LIST_DELETE(type, *list, elem, previous, next);\ | |
| }\ | |
| int sglib_##type##_delete_if_member(type **list, type *elem, type **member) {\ | |
| SGLIB_DL_LIST_DELETE_IF_MEMBER(type, *list, elem, comparator, previous, next, *member);\ | |
| return(*member!=NULL);\ | |
| }\ | |
| int sglib_##type##_is_member(type *list, type *elem) {\ | |
| int result;\ | |
| SGLIB_DL_LIST_IS_MEMBER(type, list, elem, previous, next, result);\ | |
| return(result);\ | |
| }\ | |
| type *sglib_##type##_find_member(type *list, type *elem) {\ | |
| type *result;\ | |
| SGLIB_DL_LIST_FIND_MEMBER(type, list, elem, comparator, previous, next, result);\ | |
| return(result);\ | |
| }\ | |
| type *sglib_##type##_get_first(type *list) {\ | |
| type *result;\ | |
| SGLIB_DL_LIST_GET_FIRST(type, list, previous, next, result);\ | |
| return(result);\ | |
| }\ | |
| type *sglib_##type##_get_last(type *list) {\ | |
| type *result;\ | |
| SGLIB_DL_LIST_GET_LAST(type, list, previous, next, result);\ | |
| return(result);\ | |
| }\ | |
| void sglib_##type##_sort(type **list) {\ | |
| SGLIB_DL_LIST_SORT(type, *list, comparator, previous, next);\ | |
| }\ | |
| int sglib_##type##_len(type *list) {\ | |
| int res;\ | |
| SGLIB_DL_LIST_LEN(type, list, previous, next, res);\ | |
| return(res);\ | |
| }\ | |
| void sglib_##type##_reverse(type **list) {\ | |
| SGLIB_DL_LIST_REVERSE(type, *list, previous, next);\ | |
| }\ | |
| \ | |
| type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *list, int (*subcomparator)(type *, type *), type *equalto) {\ | |
| it->subcomparator = subcomparator;\ | |
| it->equalto = equalto;\ | |
| it->prevelem = list;\ | |
| it->nextelem = list;\ | |
| if (list != NULL) it->nextelem = list->next;\ | |
| return(sglib_##type##_it_next(it));\ | |
| }\ | |
| type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *list) {\ | |
| return(sglib_##type##_it_init_on_equal(it, list, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ | |
| return(it->currentelem);\ | |
| }\ | |
| type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ | |
| type *ce, *eq;\ | |
| int (*scp)(type *, type *);\ | |
| ce = it->prevelem;\ | |
| it->prevelem = NULL;\ | |
| if (it->subcomparator != NULL) {\ | |
| eq = it->equalto;\ | |
| scp = it->subcomparator;\ | |
| while (ce!=NULL && scp(eq, ce)!=0) ce = ce->previous;\ | |
| }\ | |
| if (ce != NULL) {\ | |
| it->prevelem = ce->previous;\ | |
| } else {\ | |
| ce = it->nextelem;\ | |
| it->nextelem = NULL;\ | |
| if (it->subcomparator != NULL) {\ | |
| eq = it->equalto;\ | |
| scp = it->subcomparator;\ | |
| while (ce!=NULL && scp(ce, eq)!=0) ce = ce->next;\ | |
| }\ | |
| if (ce != NULL) it->nextelem = ce->next;\ | |
| }\ | |
| it->currentelem = ce;\ | |
| return(ce);\ | |
| } | |
| /* --------------------------------- red-black trees (level 1) -------------------------------- */ | |
| /* | |
| This implementation requires pointers to left and right sons (no | |
| parent pointer is needed) and one bit of additional information | |
| storing the color of the node. The implementation follows discrepancy | |
| fixing rules from: | |
| http://www.cis.ohio-state.edu/~gurari/course/cis680/cis680Ch11.html | |
| */ | |
| #define SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, leftt, rightt, bits, RED, BLACK) {\ | |
| type *t, *tl, *a, *b, *c, *ar, *bl, *br, *cl, *cr;\ | |
| (void)(bl);\ | |
| (void)(ar);\ | |
| t = *tree;\ | |
| tl = t->leftt;\ | |
| if (t->rightt!=NULL && SGLIB___GET_VALUE(t->rightt->bits)==RED) {\ | |
| if (SGLIB___GET_VALUE(tl->bits)==RED) {\ | |
| if ((tl->leftt!=NULL && SGLIB___GET_VALUE(tl->leftt->bits)==RED)\ | |
| || (tl->rightt!=NULL && SGLIB___GET_VALUE(tl->rightt->bits)==RED)) {\ | |
| SGLIB___SET_VALUE(t->leftt->bits,BLACK);\ | |
| SGLIB___SET_VALUE(t->rightt->bits,BLACK);\ | |
| SGLIB___SET_VALUE(t->bits,RED);\ | |
| }\ | |
| }\ | |
| } else {\ | |
| if (SGLIB___GET_VALUE(tl->bits)==RED) {\ | |
| if (tl->leftt!=NULL && SGLIB___GET_VALUE(tl->leftt->bits)==RED) {\ | |
| a = t; b = tl; c = tl->leftt;\ | |
| br = b->rightt;\ | |
| a->leftt = br;\ | |
| b->leftt = c; b->rightt = a;\ | |
| SGLIB___SET_VALUE(a->bits,RED);\ | |
| SGLIB___SET_VALUE(b->bits,BLACK);\ | |
| *tree = b;\ | |
| } else if (tl->rightt!=NULL && SGLIB___GET_VALUE(tl->rightt->bits)==RED) {\ | |
| a = t; b = tl; ar=a->rightt;\ | |
| bl=b->leftt; c=b->rightt;\ | |
| cl=c->leftt; cr=c->rightt;\ | |
| b->rightt = cl;\ | |
| a->leftt = cr;\ | |
| c->leftt = b;\ | |
| c->rightt = a;\ | |
| SGLIB___SET_VALUE(c->bits,BLACK);\ | |
| SGLIB___SET_VALUE(a->bits,RED);\ | |
| *tree = c;\ | |
| }\ | |
| }\ | |
| }\ | |
| } | |
| #define SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, leftt, rightt, bits, RED, BLACK, res) {\ | |
| type *t, *a, *b, *c, *d, *ar, *bl, *br, *cl, *cr, *dl, *dr;\ | |
| (void)(ar);\ | |
| t = a = *tree;\ | |
| assert(t!=NULL);\ | |
| ar = a->rightt;\ | |
| b = t->leftt;\ | |
| if (b==NULL) {\ | |
| assert(SGLIB___GET_VALUE(t->bits)==RED);\ | |
| SGLIB___SET_VALUE(t->bits,BLACK);\ | |
| res = 0;\ | |
| } else {\ | |
| bl = b->leftt;\ | |
| br = b->rightt;\ | |
| if (SGLIB___GET_VALUE(b->bits)==RED) {\ | |
| if (br==NULL) {\ | |
| *tree = b;\ | |
| SGLIB___SET_VALUE(b->bits,BLACK);\ | |
| b->rightt = a;\ | |
| a->leftt = br;\ | |
| res = 0;\ | |
| } else {\ | |
| c = br;\ | |
| assert(c!=NULL && SGLIB___GET_VALUE(c->bits)==BLACK);\ | |
| cl = c->leftt;\ | |
| cr = c->rightt;\ | |
| if ((cl==NULL||SGLIB___GET_VALUE(cl->bits)==BLACK) && (cr==NULL||SGLIB___GET_VALUE(cr->bits)==BLACK)) {\ | |
| *tree = b;\ | |
| b->rightt = a;\ | |
| SGLIB___SET_VALUE(b->bits,BLACK);\ | |
| a->leftt = c;\ | |
| SGLIB___SET_VALUE(c->bits,RED);\ | |
| res = 0;\ | |
| } else if (cl!=NULL && SGLIB___GET_VALUE(cl->bits)==RED) {\ | |
| if (cr!=NULL && SGLIB___GET_VALUE(cr->bits)==RED) {\ | |
| d = cr;\ | |
| dl = d->leftt;\ | |
| dr = d->rightt;\ | |
| *tree = d;\ | |
| SGLIB___SET_VALUE(d->bits,BLACK);\ | |
| d->leftt = b;\ | |
| c->rightt = dl;\ | |
| d->rightt = a;\ | |
| a->leftt = dr;\ | |
| res = 0;\ | |
| } else {\ | |
| *tree = c;\ | |
| c->leftt = b;\ | |
| c->rightt = a;\ | |
| b->leftt = bl;\ | |
| b->rightt = cl;\ | |
| a->leftt = cr;\ | |
| SGLIB___SET_VALUE(cl->bits,BLACK);\ | |
| res = 0;\ | |
| }\ | |
| } else if (cr!=NULL && SGLIB___GET_VALUE(cr->bits)==RED) {\ | |
| assert(cl==NULL || SGLIB___GET_VALUE(cl->bits)==BLACK);\ | |
| d = cr;\ | |
| dl = d->leftt;\ | |
| dr = d->rightt;\ | |
| *tree = d;\ | |
| SGLIB___SET_VALUE(d->bits,BLACK);\ | |
| d->leftt = b;\ | |
| c->rightt = dl;\ | |
| d->rightt = a;\ | |
| a->leftt = dr;\ | |
| res = 0;\ | |
| } else {\ | |
| assert(0);\ | |
| res = 0;\ | |
| }\ | |
| }\ | |
| } else {\ | |
| if ((bl==NULL || SGLIB___GET_VALUE(bl->bits)==BLACK) && (br==NULL || SGLIB___GET_VALUE(br->bits)==BLACK)) {\ | |
| res = (SGLIB___GET_VALUE(a->bits)==BLACK);\ | |
| SGLIB___SET_VALUE(a->bits,BLACK);\ | |
| SGLIB___SET_VALUE(b->bits,RED);\ | |
| } else if (bl!=NULL && SGLIB___GET_VALUE(bl->bits)==RED) {\ | |
| if (br==NULL || SGLIB___GET_VALUE(br->bits)==BLACK) {\ | |
| *tree = b;\ | |
| SGLIB___SET_VALUE(b->bits,SGLIB___GET_VALUE(a->bits));\ | |
| SGLIB___SET_VALUE(a->bits,BLACK);\ | |
| b->rightt = a;\ | |
| a->leftt = br;\ | |
| SGLIB___SET_VALUE(bl->bits,BLACK);\ | |
| res = 0;\ | |
| } else {\ | |
| assert(bl!=NULL);\ | |
| assert(br!=NULL);\ | |
| assert(SGLIB___GET_VALUE(bl->bits)==RED);\ | |
| assert(SGLIB___GET_VALUE(br->bits)==RED);\ | |
| c = br;\ | |
| cl = c->leftt;\ | |
| cr = c->rightt;\ | |
| *tree = c;\ | |
| SGLIB___SET_VALUE(c->bits,SGLIB___GET_VALUE(a->bits));\ | |
| SGLIB___SET_VALUE(a->bits,BLACK);\ | |
| c->leftt = b;\ | |
| c->rightt = a;\ | |
| b->rightt = cl;\ | |
| a->leftt = cr;\ | |
| res = 0;\ | |
| }\ | |
| } else {\ | |
| assert(br!=NULL && SGLIB___GET_VALUE(br->bits)==RED);\ | |
| c = br;\ | |
| cl = c->leftt;\ | |
| cr = c->rightt;\ | |
| *tree = c;\ | |
| SGLIB___SET_VALUE(c->bits,SGLIB___GET_VALUE(a->bits));\ | |
| SGLIB___SET_VALUE(a->bits,BLACK);\ | |
| c->leftt = b;\ | |
| c->rightt = a;\ | |
| b->rightt = cl;\ | |
| a->leftt = cr;\ | |
| res = 0;\ | |
| }\ | |
| }\ | |
| }\ | |
| } | |
| #define SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, bits, comparator, RED, BLACK) \ | |
| static void sglib___##type##_fix_left_insertion_discrepancy(type **tree) {\ | |
| SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK);\ | |
| }\ | |
| \ | |
| static void sglib___##type##_fix_right_insertion_discrepancy(type **tree) {\ | |
| SGLIB___RBTREE_FIX_INSERTION_DISCREPANCY(type, tree, right, left, bits, RED, BLACK);\ | |
| }\ | |
| \ | |
| static int sglib___##type##_fix_left_deletion_discrepancy(type **tree) {\ | |
| int res;\ | |
| SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, right, left, bits, RED, BLACK, res);\ | |
| return(res);\ | |
| }\ | |
| \ | |
| static int sglib___##type##_fix_right_deletion_discrepancy(type **tree) {\ | |
| int res;\ | |
| SGLIB___RBTREE_FIX_DELETION_DISCREPANCY(type, tree, left, right, bits, RED, BLACK, res);\ | |
| return(res);\ | |
| }\ | |
| \ | |
| static void sglib___##type##_add_recursive(type **tree, type *elem) {\ | |
| int cmp;\ | |
| type *t;\ | |
| t = *tree;\ | |
| if (t == NULL) {\ | |
| SGLIB___SET_VALUE(elem->bits,RED);\ | |
| *tree =elem;\ | |
| } else {\ | |
| cmp = comparator(elem, t);\ | |
| if (cmp < 0 || (cmp==0 && elem<t)) {\ | |
| sglib___##type##_add_recursive(&t->left, elem);\ | |
| if (SGLIB___GET_VALUE(t->bits)==BLACK) sglib___##type##_fix_left_insertion_discrepancy(tree);\ | |
| } else {\ | |
| sglib___##type##_add_recursive(&t->right, elem);\ | |
| if (SGLIB___GET_VALUE(t->bits)==BLACK) sglib___##type##_fix_right_insertion_discrepancy(tree);\ | |
| }\ | |
| }\ | |
| }\ | |
| \ | |
| static int sglib___##type##_delete_rightmost_leaf(type **tree, type **theLeaf) {\ | |
| type *t;\ | |
| int res, deepDecreased;\ | |
| t = *tree;\ | |
| res = 0;\ | |
| assert(t!=NULL);\ | |
| if (t->right == NULL) {\ | |
| *theLeaf = t;\ | |
| if (t->left!=NULL) {\ | |
| if (SGLIB___GET_VALUE(t->bits)==BLACK && SGLIB___GET_VALUE(t->left->bits)==BLACK) res = 1;\ | |
| SGLIB___SET_VALUE(t->left->bits,BLACK);\ | |
| *tree = t->left;\ | |
| } else {\ | |
| *tree = NULL;\ | |
| res = (SGLIB___GET_VALUE(t->bits)==BLACK);\ | |
| }\ | |
| } else {\ | |
| deepDecreased = sglib___##type##_delete_rightmost_leaf(&t->right, theLeaf);\ | |
| if (deepDecreased) res = sglib___##type##_fix_right_deletion_discrepancy(tree);\ | |
| }\ | |
| return(res);\ | |
| }\ | |
| \ | |
| int sglib___##type##_delete_recursive(type **tree, type *elem) {\ | |
| type *t, *theLeaf;\ | |
| int cmp, res, deepDecreased;\ | |
| t = *tree;\ | |
| res = 0;\ | |
| if (t==NULL) {\ | |
| assert(0 && "The element to delete not found in the tree, use 'delete_if_member'"!=NULL);\ | |
| } else {\ | |
| cmp = comparator(elem, t);\ | |
| if (cmp < 0 || (cmp==0 && elem<t)) {\ | |
| deepDecreased = sglib___##type##_delete_recursive(&t->left, elem);\ | |
| if (deepDecreased) {\ | |
| res = sglib___##type##_fix_left_deletion_discrepancy(tree);\ | |
| }\ | |
| } else if (cmp > 0 || (cmp==0 && elem>t)) {\ | |
| deepDecreased = sglib___##type##_delete_recursive(&t->right, elem);\ | |
| if (deepDecreased) {\ | |
| res = sglib___##type##_fix_right_deletion_discrepancy(tree);\ | |
| }\ | |
| } else {\ | |
| assert(elem==t && "Deleting an element which is non member of the tree, use 'delete_if_member'"!=NULL);\ | |
| if (t->left == NULL) {\ | |
| if (t->right == NULL) {\ | |
| /* a leaf, delete, it; */\ | |
| *tree = NULL;\ | |
| res = (SGLIB___GET_VALUE(t->bits)==BLACK);\ | |
| } else {\ | |
| if (SGLIB___GET_VALUE(t->bits)==0 && SGLIB___GET_VALUE(t->right->bits)==0) res = 1;\ | |
| SGLIB___SET_VALUE(t->right->bits,BLACK);\ | |
| *tree = t->right;\ | |
| }\ | |
| } else {\ | |
| /* propagate deletion until righmost leaf of left subtree */\ | |
| deepDecreased = sglib___##type##_delete_rightmost_leaf(&t->left, &theLeaf);\ | |
| theLeaf->left = t->left;\ | |
| theLeaf->right = t->right;\ | |
| SGLIB___SET_VALUE(theLeaf->bits,SGLIB___GET_VALUE(t->bits));\ | |
| *tree = theLeaf;\ | |
| if (deepDecreased) res = sglib___##type##_fix_left_deletion_discrepancy(tree);\ | |
| }\ | |
| }\ | |
| }\ | |
| return(res);\ | |
| }\ | |
| \ | |
| void sglib_##type##_add(type **tree, type *elem) {\ | |
| elem->left = elem->right = NULL;\ | |
| sglib___##type##_add_recursive(tree, elem);\ | |
| SGLIB___SET_VALUE((*tree)->bits,BLACK);\ | |
| }\ | |
| \ | |
| void sglib_##type##_delete(type **tree, type *elem) {\ | |
| sglib___##type##_delete_recursive(tree, elem);\ | |
| if (*tree!=NULL) SGLIB___SET_VALUE((*tree)->bits,BLACK);\ | |
| }\ | |
| \ | |
| type *sglib_##type##_find_member(type *t, type *elem) {\ | |
| type *res;\ | |
| SGLIB___BIN_TREE_FIND_MEMBER(type, t, elem, left, right, comparator, res);\ | |
| return(res);\ | |
| }\ | |
| \ | |
| int sglib_##type##_is_member(type *t, type *elem) {\ | |
| int cmp;\ | |
| while (t!=NULL) {\ | |
| cmp = comparator(elem, t);\ | |
| if (cmp < 0 || (cmp==0 && elem<t)) {\ | |
| t = t->left;\ | |
| } else if (cmp > 0 || (cmp==0 && elem>t)) {\ | |
| t = t->right;\ | |
| } else {\ | |
| assert(t == elem);\ | |
| return(1);\ | |
| }\ | |
| }\ | |
| return(0);\ | |
| }\ | |
| \ | |
| int sglib_##type##_delete_if_member(type **tree, type *elem, type **memb) {\ | |
| if ((*memb=sglib_##type##_find_member(*tree, elem))!=NULL) {\ | |
| sglib_##type##_delete(tree, *memb);\ | |
| return(1);\ | |
| } else {\ | |
| return(0);\ | |
| }\ | |
| }\ | |
| int sglib_##type##_add_if_not_member(type **tree, type *elem, type **memb) {\ | |
| if ((*memb=sglib_##type##_find_member(*tree, elem))==NULL) {\ | |
| sglib_##type##_add(tree, elem);\ | |
| return(1);\ | |
| } else {\ | |
| return(0);\ | |
| }\ | |
| }\ | |
| int sglib_##type##_len(type *t) {\ | |
| int n;\ | |
| type *e;\ | |
| (void)(e);\ | |
| n = 0;\ | |
| SGLIB_BIN_TREE_MAP_ON_ELEMENTS(type, t, e, left, right, n++);\ | |
| return(n);\ | |
| }\ | |
| \ | |
| void sglib__##type##_it_compute_current_elem(struct sglib_##type##_iterator *it) {\ | |
| int i,j;\ | |
| type *s, *eqt;\ | |
| int (*subcomparator)(type *, type *);\ | |
| eqt = it->equalto;\ | |
| subcomparator = it->subcomparator;\ | |
| it->currentelem = NULL;\ | |
| while(it->pathi > 0 && it->currentelem==NULL) {\ | |
| i = it->pathi-1;\ | |
| if (i >= 0) {\ | |
| if (it->pass[i] >= 2) {\ | |
| /* goto up */\ | |
| it->pathi --;\ | |
| } else {\ | |
| if (it->pass[i] == 0) {\ | |
| /* goto left */\ | |
| s = it->path[i]->left;\ | |
| } else {\ | |
| /* goto right */\ | |
| s = it->path[i]->right;\ | |
| }\ | |
| if (eqt != NULL) {\ | |
| if (subcomparator == NULL) {\ | |
| SGLIB___BIN_TREE_FIND_MEMBER(type, s, eqt, left, right, comparator, s);\ | |
| } else {\ | |
| SGLIB___BIN_TREE_FIND_MEMBER(type, s, eqt, left, right, subcomparator, s);\ | |
| }\ | |
| }\ | |
| if (s != NULL) {\ | |
| j = i+1;\ | |
| it->path[j] = s;\ | |
| it->pass[j] = 0;\ | |
| it->pathi ++;\ | |
| }\ | |
| it->pass[i] ++;\ | |
| }\ | |
| }\ | |
| if (it->pathi>0 && it->order == it->pass[it->pathi-1]) {\ | |
| it->currentelem = it->path[it->pathi-1];\ | |
| }\ | |
| }\ | |
| }\ | |
| type *sglib__##type##_it_init(struct sglib_##type##_iterator *it, type *tree, int order, int (*subcomparator)(type *, type *), type *equalto) {\ | |
| type *t;\ | |
| assert(it!=NULL);\ | |
| it->order = order;\ | |
| it->equalto = equalto;\ | |
| it->subcomparator = subcomparator;\ | |
| if (equalto == NULL) {\ | |
| t = tree;\ | |
| } else {\ | |
| if (subcomparator == NULL) {\ | |
| SGLIB___BIN_TREE_FIND_MEMBER(type, tree, equalto, left, right, comparator, t);\ | |
| } else {\ | |
| SGLIB___BIN_TREE_FIND_MEMBER(type, tree, equalto, left, right, subcomparator, t);\ | |
| }\ | |
| }\ | |
| if (t == NULL) {\ | |
| it->pathi = 0;\ | |
| it->currentelem = NULL;\ | |
| } else {\ | |
| it->pathi = 1;\ | |
| it->pass[0] = 0;\ | |
| it->path[0] = t;\ | |
| if (order == 0) {\ | |
| it->currentelem = t;\ | |
| } else {\ | |
| sglib__##type##_it_compute_current_elem(it);\ | |
| }\ | |
| }\ | |
| return(it->currentelem);\ | |
| }\ | |
| type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *tree) {\ | |
| return(sglib__##type##_it_init(it, tree, 2, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_init_preorder(struct sglib_##type##_iterator *it, type *tree) {\ | |
| return(sglib__##type##_it_init(it, tree, 0, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_init_inorder(struct sglib_##type##_iterator *it, type *tree) {\ | |
| return(sglib__##type##_it_init(it, tree, 1, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_init_postorder(struct sglib_##type##_iterator *it, type *tree) {\ | |
| return(sglib__##type##_it_init(it, tree, 2, NULL, NULL));\ | |
| }\ | |
| type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *tree, int (*subcomparator)(type *, type *), type *equalto) {\ | |
| return(sglib__##type##_it_init(it, tree, 1, subcomparator, equalto));\ | |
| }\ | |
| type *sglib_##type##_it_current(struct sglib_##type##_iterator *it) {\ | |
| return(it->currentelem);\ | |
| }\ | |
| type *sglib_##type##_it_next(struct sglib_##type##_iterator *it) {\ | |
| sglib__##type##_it_compute_current_elem(it);\ | |
| return(it->currentelem);\ | |
| }\ | |
| \ | |
| static void sglib___##type##_consistency_check_recursive(type *t, int *pathdeep, int cdeep) {\ | |
| if (t==NULL) {\ | |
| if (*pathdeep < 0) *pathdeep = cdeep;\ | |
| else assert(*pathdeep == cdeep);\ | |
| } else {\ | |
| if (t->left!=NULL) assert(comparator(t->left, t) <= 0);\ | |
| if (t->right!=NULL) assert(comparator(t, t->right) <= 0);\ | |
| if (SGLIB___GET_VALUE(t->bits) == RED) {\ | |
| assert(t->left == NULL || SGLIB___GET_VALUE(t->left->bits)==BLACK);\ | |
| assert(t->right == NULL || SGLIB___GET_VALUE(t->right->bits)==BLACK);\ | |
| sglib___##type##_consistency_check_recursive(t->left, pathdeep, cdeep);\ | |
| sglib___##type##_consistency_check_recursive(t->right, pathdeep, cdeep);\ | |
| } else {\ | |
| sglib___##type##_consistency_check_recursive(t->left, pathdeep, cdeep+1);\ | |
| sglib___##type##_consistency_check_recursive(t->right, pathdeep, cdeep+1);\ | |
| }\ | |
| }\ | |
| }\ | |
| \ | |
| void sglib___##type##_consistency_check(type *t) {\ | |
| int pathDeep;\ | |
| assert(t==NULL || SGLIB___GET_VALUE(t->bits) == BLACK);\ | |
| pathDeep = -1;\ | |
| sglib___##type##_consistency_check_recursive(t, &pathDeep, 0);\ | |
| } | |
| #define SGLIB_DEFINE_RBTREE_PROTOTYPES(type, left, right, colorbit, comparator) \ | |
| struct sglib_##type##_iterator {\ | |
| type *currentelem;\ | |
| char pass[SGLIB_MAX_TREE_DEEP];\ | |
| type *path[SGLIB_MAX_TREE_DEEP];\ | |
| short int pathi;\ | |
| short int order;\ | |
| type *equalto;\ | |
| int (*subcomparator)(type *, type *);\ | |
| };\ | |
| extern void sglib___##type##_consistency_check(type *t);\ | |
| extern void sglib_##type##_add(type **tree, type *elem);\ | |
| extern int sglib_##type##_add_if_not_member(type **tree, type *elem, type **memb);\ | |
| extern void sglib_##type##_delete(type **tree, type *elem);\ | |
| extern int sglib_##type##_delete_if_member(type **tree, type *elem, type **memb);\ | |
| extern int sglib_##type##_is_member(type *t, type *elem);\ | |
| extern type *sglib_##type##_find_member(type *t, type *elem);\ | |
| extern int sglib_##type##_len(type *t);\ | |
| extern type *sglib_##type##_it_init(struct sglib_##type##_iterator *it, type *tree);\ | |
| extern type *sglib_##type##_it_init_preorder(struct sglib_##type##_iterator *it, type *tree);\ | |
| extern type *sglib_##type##_it_init_inorder(struct sglib_##type##_iterator *it, type *tree);\ | |
| extern type *sglib_##type##_it_init_postorder(struct sglib_##type##_iterator *it, type *tree);\ | |
| extern type *sglib_##type##_it_init_on_equal(struct sglib_##type##_iterator *it, type *tree, int (*subcomparator)(type *, type *), type *equalto);\ | |
| extern type *sglib_##type##_it_current(struct sglib_##type##_iterator *it);\ | |
| extern type *sglib_##type##_it_next(struct sglib_##type##_iterator *it);\ | |
| #define SGLIB_DEFINE_RBTREE_FUNCTIONS(type, left, right, colorbit, comparator) \ | |
| SGLIB_DEFINE_RBTREE_FUNCTIONS_GENERAL(type, left, right, colorbit, comparator, 1, 0) | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* - SUPPLEMENTARY DEFINITIONS - */ | |
| /* ---------------------------------------------------------------------------- */ | |
| /* ---------------------------------------------------------------------------- */ | |
| #define SGLIB___GET_VALUE(x) (x) | |
| #define SGLIB___SET_VALUE(x, value) {(x) = (value);} | |
| #define SGLIB_ARRAY_ELEMENTS_EXCHANGER(type, a, i, j) {type _sgl_aee_tmp_; _sgl_aee_tmp_=(a)[(i)]; (a)[(i)]=(a)[(j)]; (a)[(j)]= _sgl_aee_tmp_;} | |
| #define SGLIB_SAFE_NUMERIC_COMPARATOR(x, y) (((x)>(y)?1:((x)<(y)?-1:0))) | |
| #define SGLIB_SAFE_REVERSE_NUMERIC_COMPARATOR(x, y) (((x)>(y)?-1:((x)<(y)?1:0))) | |
| #define SGLIB_FAST_NUMERIC_COMPARATOR(x, y) ((int)((x) - (y))) | |
| #define SGLIB_FAST_REVERSE_NUMERIC_COMPARATOR(x, y) ((int)((y) - (x))) | |
| #define SGLIB_NUMERIC_COMPARATOR(x, y) SGLIB_SAFE_NUMERIC_COMPARATOR(x, y) | |
| #define SGLIB_REVERSE_NUMERIC_COMPARATOR(x, y) SGLIB_SAFE_REVERSE_NUMERIC_COMPARATOR(x, y) | |
| #ifndef SGLIB_MAX_TREE_DEEP | |
| #define SGLIB_MAX_TREE_DEEP 128 | |
| #endif | |
| #ifndef SGLIB_HASH_TAB_SHIFT_CONSTANT | |
| #define SGLIB_HASH_TAB_SHIFT_CONSTANT 16381 /* should be a prime */ | |
| /* #define SGLIB_HASH_TAB_SHIFT_CONSTANT 536870912*/ /* for large tables :) */ | |
| #endif | |
| #endif /* _SGLIB__h_ */ |