blob: c5dce8541f28458968ca407c37b06c870c2d4ed6 [file] [log] [blame]
#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 */