You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
10 KiB
297 lines
10 KiB
4 months ago
|
#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 */
|