From: Sebastian Hack Date: Wed, 11 Jul 2007 22:47:45 +0000 (+0000) Subject: Added sorted array sets. X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=73a97ce11cc91fd98375f61100075af77c277629;p=libfirm Added sorted array sets. Adjusted nodesets to it but it is still deactivated. See macro at the top of irnodeset.h [r15065] --- diff --git a/include/libfirm/adt/arrayset.h b/include/libfirm/adt/arrayset.h new file mode 100644 index 000000000..e17cb8699 --- /dev/null +++ b/include/libfirm/adt/arrayset.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. + * + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/** + * @file arrayset.h + * @date 11.07.2007 + * @author Sebastian Hack + */ + +struct HashSet { + ValueType *arr; +#ifndef NDEBUG + unsigned in_order : 1; +#endif +#ifdef ADDITIONAL_DATA + ADDITIONAL_DATA +#endif +}; + +struct HashSetIterator { + ValueType *arr; + int curr; +}; diff --git a/ir/adt/arrayset.c b/ir/adt/arrayset.c new file mode 100644 index 000000000..ab3d7d48c --- /dev/null +++ b/ir/adt/arrayset.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. + * + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/** + * @file arrayset.c + * @brief Implementation of sets with sorted arrays. + * @date 11.07.2007 + * @author Sebastian Hack + * + * Follows the same API/specialization scheme as hashset.c and is thus interchangable. + * To remain compatible, all specializations as in hashset.c must be done. + * Additionally, we need a ValueCmp macro comapring two values not only for equality. + * That macro follows the same scheme as the compare functions in qsort(3). + */ + +#ifdef HashSet + +#include "firm_config.h" +#include "array.h" + +static INLINE int hashset_bsearch(ValueType *arr, const ValueType elm) +{ + int res = 0; + int lo = 0; + int hi = ARR_LEN(arr); + + while(lo < hi) { + int md = lo + ((hi - lo) >> 1); + int cmp = ValueCmp(arr[md], elm); + + if(cmp < 0) + lo = md + 1; + else if(cmp > 0) + hi = md; + else { + res = md; + break; + } + + res = lo; + } + + return res; +} + +static INLINE int hashset_is_at(ValueType *arr, int idx, const ValueType what) +{ + return idx < ARR_LEN(arr) && ValueCmp(arr[idx], what) == 0; +} + +void hashset_init_size(HashSet *set, size_t expected_elements) +{ + set->arr = NEW_ARR_F(ValueType, expected_elements); +#ifndef NDEBUG + set->in_order = 1; +#endif + ARR_SHRINKLEN(set->arr, 0); +} + +void hashset_init(HashSet *set) +{ + hashset_init_size(set, 16); +} + +void hashset_destroy(HashSet *set) +{ + DEL_ARR_F(set->arr); +} + +int hashset_insert(HashSet *set, ValueType elt) +{ + ValueType *arr = set->arr; + int i, idx = hashset_bsearch(arr, elt); + +#ifndef NDEBUG + assert(set->in_order); +#endif + if (!hashset_is_at(arr, idx, elt)) { + ARR_EXTEND(ValueType, set->arr, 1); + arr = set->arr; + for (i = ARR_LEN(arr) - 1; i > idx; --i) + arr[i] = arr[i - 1]; + arr[idx] = elt; + return 1; + } + + return 0; +} + +void hashset_insert_quick(HashSet *set, ValueType elt) +{ + ValueType *arr = set->arr; + ARR_EXTEND(ValueType, set->arr, 1); + arr = set->arr; + arr[ARR_LEN(arr) - 1] = elt; +} + +static INLINE int _hashset_remove_idx(ValueType *arr, int idx) +{ + int n; + + for (n = ARR_LEN(arr) - 1; idx < n; ++idx) + arr[idx] = arr[idx + 1]; + + return n; +} + +void hashset_remove(HashSet *set, const ValueType elt) +{ + ValueType *arr = set->arr; + int idx = hashset_bsearch(arr, elt); + +#ifndef NDEBUG + assert(set->in_order); +#endif + if (hashset_is_at(arr, idx, elt)) { + int new_len = _hashset_remove_idx(arr, idx); + ARR_SHRINKLEN(arr, new_len); + } +} + +void hashset_remove_quick(HashSet *set, const ValueType elt) +{ + ValueType *arr = set->arr; + int idx = hashset_bsearch(arr, elt); + +#ifndef NDEBUG + set->in_order = 0; +#endif + if (hashset_is_at(arr, idx, elt)) { + int n = ARR_LEN(arr); + if (idx < n - 1) + arr[idx] = arr[n - 1]; + ARR_SHRINKLEN(arr, n - 1); + } +} + +void hashset_fixup(HashSet *set) +{ + ValueType *arr = set->arr; + ValueType *tmp; + int i, n; + + CLONE_ARR_A(ValueType, tmp, arr); + + memcpy(tmp, arr, n * sizeof(arr[0])); + ARR_SHRINKLEN(arr, 0); + for (i = 0, n = ARR_LEN(arr); i < n; ++i) + hashset_insert(set, tmp[0]); +#ifndef NDEBUG + set->in_order = 1; +#endif +} + +ValueType hashset_find(const HashSet *set, const ValueType elt) +{ + int idx = hashset_bsearch(set->arr, elt); +#ifndef NDEBUG + assert(set->in_order); +#endif + return hashset_is_at(set->arr, idx, elt) ? set->arr[idx] : NullValue; +} + +size_t hashset_size(const HashSet *set) +{ + return ARR_LEN(set->arr); +} + +void hashset_iterator_init(HashSetIterator *iter, const HashSet *set) +{ + iter->arr = set->arr; + iter->curr = -1; +} + +ValueType ir_nodeset_iterator_next(HashSetIterator *iter) +{ + ++iter->curr; + return iter->curr < ARR_LEN(iter->arr) ? iter->arr[iter->curr] : NullValue; +} + +void hashset_remove_iterator(HashSet *set, const HashSetIterator *iter) +{ + (void) set; + (void) _hashset_remove_idx(iter->arr, iter->curr); + ARR_SHRINKLEN(iter->arr, ARR_LEN(iter->arr) - 1); +} + +#endif diff --git a/ir/ir/irnodeset.c b/ir/ir/irnodeset.c index bac3fb00d..ec325f5fd 100644 --- a/ir/ir/irnodeset.c +++ b/ir/ir/irnodeset.c @@ -45,6 +45,7 @@ #endif #define KeysEqual(this,key1,key2) (key1) == (key2) #define SetRangeEmpty(ptr,size) memset(ptr, 0, (size) * sizeof((ptr)[0])) +#define ValueCmp(a,b) ((int) get_irn_idx(a) - (int) get_irn_idx(b)) #define hashset_init _ir_nodeset_init #define hashset_init_size ir_nodeset_init_size @@ -57,8 +58,19 @@ #define hashset_iterator_next ir_nodeset_iterator_next #define hashset_remove_iterator ir_nodeset_remove_iterator +#ifdef IR_NODESET_USE_ORDERED_SETS + +#define hashset_insert_quick ir_nodeset_insert_quick +#define hashset_remove_quick ir_nodeset_remove_quick +#define hashset_fixup ir_nodeset_fixup +#include "arrayset.c" + +#else + #include "hashset.c" +#endif /* IR_NODESET_USE_ORDERED_SETS */ + void ir_nodeset_init(ir_nodeset_t *nodeset) { ir_nodeset_init_size(nodeset, 16); @@ -66,5 +78,5 @@ void ir_nodeset_init(ir_nodeset_t *nodeset) int ir_nodeset_contains(const ir_nodeset_t *this, const ir_node *node) { - return _ir_nodeset_find(this, node); + return _ir_nodeset_find(this, node) != NULL; } diff --git a/ir/ir/irnodeset.h b/ir/ir/irnodeset.h index 56a7df849..d60bf5fb2 100644 --- a/ir/ir/irnodeset.h +++ b/ir/ir/irnodeset.h @@ -33,11 +33,27 @@ #include "firm_types.h" #include "xmalloc.h" +/* + * sebastian experimental: + * use ordered arrays as node sets. + * the guys here have made good experiences with that. + * Internally we use normal Firm arrays and binary + * search for locating the elements. Using arrays should + * give the sets a small footprint. + */ +#undef IR_NODESET_USE_ORDERED_SETS + #define HashSet ir_nodeset_t #define HashSetIterator ir_nodeset_iterator_t #define ValueType ir_node* #define DO_REHASH + +#ifdef IR_NODESET_USE_ORDERED_SETS +#include "arrayset.h" +#else #include "hashset.h" +#endif + #undef DO_REHASH #undef ValueType #undef HashSetIterator @@ -99,6 +115,7 @@ static INLINE void ir_nodeset_del(ir_nodeset_t *nodeset) { */ int ir_nodeset_insert(ir_nodeset_t *nodeset, ir_node *node); + /** * Removes a node from a nodeset. Does nothing if the nodeset doesn't contain * the node. @@ -160,4 +177,46 @@ void ir_nodeset_remove_iterator(ir_nodeset_t *nodeset, irn = ir_nodeset_iterator_next(&iter); \ irn != NULL; irn = ir_nodeset_iterator_next(&iter)) + +#ifdef IR_NODESET_USE_ORDERED_SETS + +/** + * Insert an element quickly into from the set. + * This method may destroy internal invariats of the set (think of sorted arrays). + * All calls to other routines but + * - iteration + * - get the number of elements in the set + * will not work until ir_nodeset_fixup() was called. + * @param nodeset The nodeset. + * @param node The node to insert. + */ +void ir_nodeset_insert_quick(ir_nodeset_t *nodeset, ir_node *node); + +/** + * Remove an element quickly from the set. + * This method may destroy internal invariats of the set (think of sorted arrays). + * All calls to other routines but + * - iteration + * - get the number of elements in the set + * will not work until ir_nodeset_fixup() was called. + * @param nodeset The nodeset. + * @param node The node to delete. + */ +void ir_nodeset_remove_quick(ir_nodeset_t *nodeset, const ir_node *node); + +/** + * Fixes up internal state of the set. + * Is needed when one of the _quick functions was called. + * @param nodeset The nodeset. + */ +void ir_nodeset_fixup(ir_nodeset_t *nodeset); + +#else + +#define ir_nodeset_remove_quick ir_nodeset_remove +#define ir_nodeset_insert_quick ir_nodeset_insert +#define ir_nodeset_fixup(set) + +#endif /* IR_NODESET_USE_ORDERED_SETS */ + #endif