| #ifndef _DEPOOLMULTISET_H |
| #define _DEPOOLMULTISET_H |
| /*------------------------------------------------------------------------- |
| * drawElements Memory Pool Library |
| * -------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Memory pool multiset class. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "deDefs.h" |
| #include "deMemPool.h" |
| #include "dePoolHash.h" |
| #include "deInt32.h" |
| |
| DE_BEGIN_EXTERN_C |
| |
| void dePoolMultiSet_selfTest (void); |
| |
| DE_END_EXTERN_C |
| |
| /*--------------------------------------------------------------------*//*! |
| * \brief Declare a template pool multiset class interface. |
| * \param TYPENAME Type name of the declared multiset. |
| * \param KEYTYPE Type of the key. |
| * |
| * This macro declares the interface for a multiset. For the implementation |
| * of the multiset, see DE_IMPLEMENT_POOL_MULTISET. Usually this macro is put |
| * into the header file and the implementation macro is put in some .c file. |
| * |
| * \todo [petri] Detailed description. |
| * |
| * The functions for operating the multiset are: |
| * \todo [petri] Figure out how to comment these in Doxygen-style. |
| * |
| * \code |
| * MultiSet* MultiSet_create (deMemPool* pool); |
| * int MultiSet_getNumElements (const MultiSet* set); |
| * deBool MultiSet_exists (const MultiSet* set, Key key); |
| * deBool MultiSet_insert (MultiSet* set, Key key); |
| * void MultiSet_delete (MultiSet* set, Key key); |
| * int MultiSet_getKeyCount (const MultiSet* set, Key key); |
| * deBool MultiSet_setKeyCount (MultiSet* set, Key key, int count); |
| * \endcode |
| *//*--------------------------------------------------------------------*/ |
| #define DE_DECLARE_POOL_MULTISET(TYPENAME, KEYTYPE) \ |
| \ |
| DE_DECLARE_POOL_HASH(TYPENAME##Hash, KEYTYPE, int); \ |
| \ |
| typedef struct TYPENAME##_s \ |
| { \ |
| deMemPool* pool; \ |
| int numElements; \ |
| TYPENAME##Hash* hash; \ |
| } TYPENAME; /* NOLINT(TYPENAME) */ \ |
| \ |
| TYPENAME* TYPENAME##_create (deMemPool* pool); \ |
| void TYPENAME##_reset (DE_PTR_TYPE(TYPENAME) set); \ |
| deBool TYPENAME##_setKeyCount (DE_PTR_TYPE(TYPENAME) set, KEYTYPE key, int newCount); \ |
| \ |
| DE_INLINE int TYPENAME##_getNumElements (const TYPENAME* set) \ |
| { \ |
| return set->numElements; \ |
| } \ |
| \ |
| DE_INLINE int TYPENAME##_getKeyCount (const TYPENAME* set, KEYTYPE key) \ |
| { \ |
| int* countPtr = TYPENAME##Hash_find(set->hash, key); \ |
| int count = countPtr ? *countPtr : 0; \ |
| DE_ASSERT(count > 0 || !countPtr); \ |
| return count; \ |
| } \ |
| \ |
| DE_INLINE deBool TYPENAME##_exists (const TYPENAME* set, KEYTYPE key) \ |
| { \ |
| return (TYPENAME##_getKeyCount(set, key) > 0); \ |
| } \ |
| \ |
| DE_INLINE deBool TYPENAME##_insert (DE_PTR_TYPE(TYPENAME) set, KEYTYPE key) \ |
| { \ |
| int oldCount = TYPENAME##_getKeyCount(set, key); \ |
| return TYPENAME##_setKeyCount(set, key, oldCount + 1); \ |
| } \ |
| \ |
| DE_INLINE void TYPENAME##_delete (DE_PTR_TYPE(TYPENAME) set, KEYTYPE key) \ |
| { \ |
| int oldCount = TYPENAME##_getKeyCount(set, key); \ |
| DE_ASSERT(oldCount > 0); \ |
| TYPENAME##_setKeyCount(set, key, oldCount - 1); \ |
| } \ |
| \ |
| struct TYPENAME##DeclareDummy_s { int dummy; } |
| |
| /*--------------------------------------------------------------------*//*! |
| * \brief Implement a template pool multiset class. |
| * \param TYPENAME Type name of the declared multiset. |
| * \param KEYTYPE Type of the key. |
| * \param HASHFUNC Function used for hashing the key. |
| * \param CMPFUNC Function used for exact matching of the keys. |
| * |
| * This macro has implements the set declared with DE_DECLARE_POOL_MULTISET. |
| * Usually this macro should be used from a .c file, since the macro expands |
| * into multiple functions. The TYPENAME and KEYTYPE parameters |
| * must match those of the declare macro. |
| *//*--------------------------------------------------------------------*/ |
| #define DE_IMPLEMENT_POOL_MULTISET(TYPENAME, KEYTYPE, HASHFUNC, CMPFUNC) \ |
| \ |
| DE_IMPLEMENT_POOL_HASH(TYPENAME##Hash, KEYTYPE, int, HASHFUNC, CMPFUNC); \ |
| \ |
| TYPENAME* TYPENAME##_create (deMemPool* pool) \ |
| { \ |
| /* Alloc struct. */ \ |
| DE_PTR_TYPE(TYPENAME) set = DE_POOL_NEW(pool, TYPENAME); \ |
| if (!set) \ |
| return DE_NULL; \ |
| \ |
| /* Init. */ \ |
| memset(set, 0, sizeof(TYPENAME)); \ |
| set->pool = pool; \ |
| \ |
| set->hash = TYPENAME##Hash_create(pool); \ |
| \ |
| return set; \ |
| } \ |
| \ |
| void TYPENAME##_reset (DE_PTR_TYPE(TYPENAME) set) \ |
| { \ |
| TYPENAME##Hash_reset(set->hash); \ |
| set->numElements = 0; \ |
| } \ |
| \ |
| deBool TYPENAME##_setKeyCount (DE_PTR_TYPE(TYPENAME) set, KEYTYPE key, int newCount) \ |
| { \ |
| int* countPtr = TYPENAME##Hash_find(set->hash, key); \ |
| int oldCount = countPtr ? *countPtr : 0; \ |
| \ |
| DE_ASSERT(oldCount > 0 || !countPtr); \ |
| DE_ASSERT(newCount >= 0); \ |
| set->numElements += (newCount - oldCount); \ |
| \ |
| if (newCount == 0 && countPtr) \ |
| TYPENAME##Hash_delete(set->hash, key); \ |
| else if (newCount > 0 && countPtr) \ |
| *countPtr = newCount; \ |
| else if (newCount > 0) \ |
| return TYPENAME##Hash_insert(set->hash, key, newCount); \ |
| return DE_TRUE; \ |
| } \ |
| \ |
| struct TYPENAME##ImplementDummy_s { int dummy; } |
| |
| /*--------------------------------------------------------------------*//*! |
| * \brief Declare set-wise operations for a multiset template. |
| * \param TYPENAME Type name of the declared set. |
| * \param KEYTYPE Type of the key. |
| * |
| * This macro declares union and intersection operations for a multiset. |
| * For implementation see DE_IMPLEMENT_POOL_MULTISET_UNION_INTERSECT. |
| * |
| * \todo [petri] Detailed description. |
| * |
| * The functions for operating the set are: |
| * \todo [petri] Figure out how to comment these in Doxygen-style. |
| * |
| * \code |
| * deBool MultiSet_union (Set* to, const Set* a, const Set* b); |
| * deBool MultiSet_unionInplace (Set* a, const Set* b); |
| * deBool MultiSet_intersect (Set* to, const Set* a, const Set* b); |
| * void MultiSet_intersectInplace (Set* a, const Set* b); |
| * deBool MultiSet_sum (Set* to, const Set* a, const Set* b); |
| * deBool MultiSet_sumInplace (Set* a, const Set* b); |
| * deBool MultiSet_difference (Set* to, const Set* a, const Set* b); |
| * void MultiSet_differenceInplace (Set* a, const Set* b); |
| * \endcode |
| *//*--------------------------------------------------------------------*/ |
| #define DE_DECLARE_POOL_MULTISET_SETWISE_OPERATIONS(TYPENAME) \ |
| deBool TYPENAME##_union (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b); \ |
| deBool TYPENAME##_unionInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b); \ |
| deBool TYPENAME##_intersect (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b); \ |
| void TYPENAME##_intersectInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b); \ |
| deBool TYPENAME##_sum (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b); \ |
| deBool TYPENAME##_sumInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b); \ |
| deBool TYPENAME##_difference (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b); \ |
| void TYPENAME##_differenceInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b); \ |
| struct TYPENAME##SetwiseDeclareDummy_s { int dummy; } |
| |
| #define DE_IMPLEMENT_POOL_MULTISET_SETWISE_OPERATIONS(TYPENAME, KEYTYPE) \ |
| deBool TYPENAME##_union (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b) \ |
| { \ |
| TYPENAME##_reset(to); \ |
| return TYPENAME##_unionInplace(to, a) && TYPENAME##_unionInplace(to, b); \ |
| } \ |
| \ |
| deBool TYPENAME##_unionInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b) \ |
| { \ |
| TYPENAME##HashIter iter; \ |
| for (TYPENAME##HashIter_init(b, &iter); \ |
| TYPENAME##HashIter_hasItem(&iter); \ |
| TYPENAME##HashIter_next(&iter)) \ |
| { \ |
| KEYTYPE key = TYPENAME##HashIter_getKey(&iter); \ |
| int bCount = TYPENAME##HashIter_getValue(&iter); \ |
| int aCount = TYPENAME##_getKeyCount(a, key); \ |
| int count = deMax32(aCount, bCount); \ |
| if (bCount && !TYPENAME##_setKeyCount(a, key, aCount + bCount)) \ |
| return DE_FALSE; \ |
| } \ |
| return DE_TRUE; \ |
| } \ |
| \ |
| deBool TYPENAME##_intersect (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b) \ |
| { \ |
| TYPENAME##HashIter iter; \ |
| TYPENAME##_reset(to); \ |
| for (TYPENAME##HashIter_init(a, &iter); \ |
| TYPENAME##HashIter_hasItem(&iter); \ |
| TYPENAME##HashIter_next(&iter)) \ |
| { \ |
| KEYTYPE key = TYPENAME##HashIter_getKey(&iter); \ |
| int aCount = TYPENAME##HashIter_getValue(&iter); \ |
| int bCount = TYPENAME##_getKeyValue(b, key); \ |
| int count = deMin32(aCount, bCount); \ |
| if (count && !TYPENAME##_setKeyCount(to, key, count)) \ |
| return DE_FALSE; \ |
| } \ |
| return DE_TRUE; \ |
| } \ |
| \ |
| void TYPENAME##_intersectInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b) \ |
| { \ |
| DE_FATAL("Not implemented."); \ |
| } \ |
| \ |
| deBool TYPENAME##_sum (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b) \ |
| { \ |
| TYPENAME##_reset(to); \ |
| return TYPENAME##_sumInplace(to, a) && TYPENAME##_sumInplace(to, b); \ |
| } \ |
| \ |
| deBool TYPENAME##_sumInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b) \ |
| { \ |
| TYPENAME##HashIter iter; \ |
| for (TYPENAME##HashIter_init(b, &iter); \ |
| TYPENAME##HashIter_hasItem(&iter); \ |
| TYPENAME##HashIter_next(&iter)) \ |
| { \ |
| KEYTYPE key = TYPENAME##HashIter_getKey(&iter); \ |
| int aCount = TYPENAME##_getKeyValue(a, key); \ |
| int bCount = TYPENAME##HashIter_getValue(&iter); \ |
| int count = aCount + bCount; \ |
| if (!TYPENAME##_setKeyCount(a, key, count)) \ |
| return DE_FALSE; \ |
| } \ |
| } \ |
| \ |
| deBool TYPENAME##_difference (DE_PTR_TYPE(TYPENAME) to, const TYPENAME* a, const TYPENAME* b) \ |
| { \ |
| TYPENAME##HashIter iter; \ |
| TYPENAME##_reset(to); \ |
| for (TYPENAME##HashIter_init(a, &iter); \ |
| TYPENAME##HashIter_hasItem(&iter); \ |
| TYPENAME##HashIter_next(&iter)) \ |
| { \ |
| KEYTYPE key = TYPENAME##HashIter_getKey(&iter); \ |
| int aCount = TYPENAME##HashIter_getValue(&iter); \ |
| int bCount = TYPENAME##_getKeyValue(b, key); \ |
| int count = deMax32(0, aCount - bCount); \ |
| if (count && !TYPENAME##_setKeyCount(to, key, count)) \ |
| return DE_FALSE; \ |
| } \ |
| return DE_TRUE; \ |
| } \ |
| \ |
| void TYPENAME##_differenceInplace (DE_PTR_TYPE(TYPENAME) a, const TYPENAME* b) \ |
| { \ |
| DE_FATAL("Not implemented."); \ |
| } \ |
| \ |
| struct TYPENAME##SetwiseImplementDummy_s { int dummy; } |
| |
| #endif /* _DEPOOLMULTISET_H */ |