/** * WinPR: Windows Portable Runtime * Collections * * Copyright 2012 Marc-Andre Moreau * * 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. */ #ifndef WINPR_COLLECTIONS_H #define WINPR_COLLECTIONS_H #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef void* (*OBJECT_NEW_FN)(void* val); typedef void (*OBJECT_INIT_FN)(void* obj); typedef void (*OBJECT_UNINIT_FN)(void* obj); typedef void (*OBJECT_FREE_FN)(void* obj); typedef BOOL (*OBJECT_EQUALS_FN)(const void* objA, const void* objB); struct _wObject { OBJECT_NEW_FN fnObjectNew; OBJECT_INIT_FN fnObjectInit; OBJECT_UNINIT_FN fnObjectUninit; OBJECT_FREE_FN fnObjectFree; OBJECT_EQUALS_FN fnObjectEquals; }; typedef struct _wObject wObject; /* System.Collections.Queue */ struct _wQueue { int capacity; int growthFactor; BOOL synchronized; int head; int tail; int size; void** array; CRITICAL_SECTION lock; HANDLE event; wObject object; }; typedef struct _wQueue wQueue; WINPR_API int Queue_Count(wQueue* queue); WINPR_API void Queue_Lock(wQueue* queue); WINPR_API void Queue_Unlock(wQueue* queue); WINPR_API HANDLE Queue_Event(wQueue* queue); #define Queue_Object(_queue) (&_queue->object) WINPR_API void Queue_Clear(wQueue* queue); WINPR_API BOOL Queue_Contains(wQueue* queue, void* obj); WINPR_API BOOL Queue_Enqueue(wQueue* queue, void* obj); WINPR_API void* Queue_Dequeue(wQueue* queue); WINPR_API void* Queue_Peek(wQueue* queue); WINPR_API wQueue* Queue_New(BOOL synchronized, int capacity, int growthFactor); WINPR_API void Queue_Free(wQueue* queue); /* System.Collections.Stack */ struct _wStack { int size; int capacity; void** array; CRITICAL_SECTION lock; BOOL synchronized; wObject object; }; typedef struct _wStack wStack; WINPR_API int Stack_Count(wStack* stack); WINPR_API BOOL Stack_IsSynchronized(wStack* stack); #define Stack_Object(_stack) (&_stack->object) WINPR_API void Stack_Clear(wStack* stack); WINPR_API BOOL Stack_Contains(wStack* stack, void* obj); WINPR_API void Stack_Push(wStack* stack, void* obj); WINPR_API void* Stack_Pop(wStack* stack); WINPR_API void* Stack_Peek(wStack* stack); WINPR_API wStack* Stack_New(BOOL synchronized); WINPR_API void Stack_Free(wStack* stack); /* System.Collections.ArrayList */ struct _wArrayList { int capacity; int growthFactor; BOOL synchronized; int size; void** array; CRITICAL_SECTION lock; wObject object; }; typedef struct _wArrayList wArrayList; WINPR_API int ArrayList_Capacity(wArrayList* arrayList); WINPR_API int ArrayList_Count(wArrayList* arrayList); WINPR_API int ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems); WINPR_API BOOL ArrayList_IsFixedSized(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsReadOnly(wArrayList* arrayList); WINPR_API BOOL ArrayList_IsSynchronized(wArrayList* arrayList); WINPR_API void ArrayList_Lock(wArrayList* arrayList); WINPR_API void ArrayList_Unlock(wArrayList* arrayList); WINPR_API void* ArrayList_GetItem(wArrayList* arrayList, int index); WINPR_API void ArrayList_SetItem(wArrayList* arrayList, int index, void* obj); #define ArrayList_Object(_arrayList) (&_arrayList->object) #define ArrayList_ForEach(_lst, _type, index, value) \ for (index = 0; \ index < ArrayList_Count(_lst) && (value = (_type)ArrayList_GetItem(_lst, index)); \ index++) WINPR_API void ArrayList_Clear(wArrayList* arrayList); WINPR_API BOOL ArrayList_Contains(wArrayList* arrayList, void* obj); WINPR_API int ArrayList_Add(wArrayList* arrayList, void* obj); WINPR_API BOOL ArrayList_Insert(wArrayList* arrayList, int index, void* obj); WINPR_API BOOL ArrayList_Remove(wArrayList* arrayList, void* obj); WINPR_API BOOL ArrayList_RemoveAt(wArrayList* arrayList, int index); WINPR_API int ArrayList_IndexOf(wArrayList* arrayList, void* obj, int startIndex, int count); WINPR_API int ArrayList_LastIndexOf(wArrayList* arrayList, void* obj, int startIndex, int count); WINPR_API wArrayList* ArrayList_New(BOOL synchronized); WINPR_API void ArrayList_Free(wArrayList* arrayList); /* System.Collections.DictionaryBase */ struct _wDictionary { BOOL synchronized; CRITICAL_SECTION lock; }; typedef struct _wDictionary wDictionary; /* System.Collections.Specialized.ListDictionary */ typedef struct _wListDictionaryItem wListDictionaryItem; struct _wListDictionaryItem { void* key; void* value; wListDictionaryItem* next; }; struct _wListDictionary { BOOL synchronized; CRITICAL_SECTION lock; wListDictionaryItem* head; wObject objectKey; wObject objectValue; }; typedef struct _wListDictionary wListDictionary; #define ListDictionary_KeyObject(_dictionary) (&_dictionary->objectKey) #define ListDictionary_ValueObject(_dictionary) (&_dictionary->objectValue) WINPR_API int ListDictionary_Count(wListDictionary* listDictionary); WINPR_API void ListDictionary_Lock(wListDictionary* listDictionary); WINPR_API void ListDictionary_Unlock(wListDictionary* listDictionary); WINPR_API BOOL ListDictionary_Add(wListDictionary* listDictionary, const void* key, void* value); WINPR_API void* ListDictionary_Remove(wListDictionary* listDictionary, const void* key); WINPR_API void* ListDictionary_Remove_Head(wListDictionary* listDictionary); WINPR_API void ListDictionary_Clear(wListDictionary* listDictionary); WINPR_API BOOL ListDictionary_Contains(wListDictionary* listDictionary, const void* key); WINPR_API int ListDictionary_GetKeys(wListDictionary* listDictionary, ULONG_PTR** ppKeys); WINPR_API void* ListDictionary_GetItemValue(wListDictionary* listDictionary, const void* key); WINPR_API BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, const void* key, void* value); WINPR_API wListDictionary* ListDictionary_New(BOOL synchronized); WINPR_API void ListDictionary_Free(wListDictionary* listDictionary); /* System.Collections.Generic.LinkedList */ typedef struct _wLinkedList wLinkedList; WINPR_API int LinkedList_Count(wLinkedList* list); WINPR_API void* LinkedList_First(wLinkedList* list); WINPR_API void* LinkedList_Last(wLinkedList* list); WINPR_API BOOL LinkedList_Contains(wLinkedList* list, void* value); WINPR_API void LinkedList_Clear(wLinkedList* list); WINPR_API BOOL LinkedList_AddFirst(wLinkedList* list, void* value); WINPR_API BOOL LinkedList_AddLast(wLinkedList* list, void* value); WINPR_API BOOL LinkedList_Remove(wLinkedList* list, void* value); WINPR_API void LinkedList_RemoveFirst(wLinkedList* list); WINPR_API void LinkedList_RemoveLast(wLinkedList* list); WINPR_API void LinkedList_Enumerator_Reset(wLinkedList* list); WINPR_API void* LinkedList_Enumerator_Current(wLinkedList* list); WINPR_API BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list); WINPR_API wLinkedList* LinkedList_New(void); WINPR_API void LinkedList_Free(wLinkedList* list); WINPR_API wObject* LinkedList_Object(wLinkedList* list); /* System.Collections.Generic.KeyValuePair */ typedef struct _wKeyValuePair wKeyValuePair; struct _wKeyValuePair { void* key; void* value; wKeyValuePair* next; }; /* Reference Table */ struct _wReference { UINT32 Count; void* Pointer; }; typedef struct _wReference wReference; typedef int (*REFERENCE_FREE)(void* context, void* ptr); struct _wReferenceTable { UINT32 size; CRITICAL_SECTION lock; void* context; BOOL synchronized; wReference* array; REFERENCE_FREE ReferenceFree; }; typedef struct _wReferenceTable wReferenceTable; WINPR_API UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr); WINPR_API UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr); WINPR_API wReferenceTable* ReferenceTable_New(BOOL synchronized, void* context, REFERENCE_FREE ReferenceFree); WINPR_API void ReferenceTable_Free(wReferenceTable* referenceTable); /* Countdown Event */ struct _wCountdownEvent { DWORD count; CRITICAL_SECTION lock; HANDLE event; DWORD initialCount; }; typedef struct _wCountdownEvent wCountdownEvent; WINPR_API DWORD CountdownEvent_CurrentCount(wCountdownEvent* countdown); WINPR_API DWORD CountdownEvent_InitialCount(wCountdownEvent* countdown); WINPR_API BOOL CountdownEvent_IsSet(wCountdownEvent* countdown); WINPR_API HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown); WINPR_API void CountdownEvent_AddCount(wCountdownEvent* countdown, DWORD signalCount); WINPR_API BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount); WINPR_API void CountdownEvent_Reset(wCountdownEvent* countdown, DWORD count); WINPR_API wCountdownEvent* CountdownEvent_New(DWORD initialCount); WINPR_API void CountdownEvent_Free(wCountdownEvent* countdown); /* Hash Table */ typedef UINT32 (*HASH_TABLE_HASH_FN)(void* key); typedef BOOL (*HASH_TABLE_KEY_COMPARE_FN)(void* key1, void* key2); typedef BOOL (*HASH_TABLE_VALUE_COMPARE_FN)(void* value1, void* value2); typedef void* (*HASH_TABLE_KEY_CLONE_FN)(void* key); typedef void* (*HASH_TABLE_VALUE_CLONE_FN)(void* value); typedef void (*HASH_TABLE_KEY_FREE_FN)(void* key); typedef void (*HASH_TABLE_VALUE_FREE_FN)(void* value); struct _wHashTable { BOOL synchronized; CRITICAL_SECTION lock; int numOfBuckets; int numOfElements; float idealRatio; float lowerRehashThreshold; float upperRehashThreshold; wKeyValuePair** bucketArray; HASH_TABLE_HASH_FN hash; HASH_TABLE_KEY_COMPARE_FN keyCompare; HASH_TABLE_VALUE_COMPARE_FN valueCompare; HASH_TABLE_KEY_CLONE_FN keyClone; HASH_TABLE_VALUE_CLONE_FN valueClone; HASH_TABLE_KEY_FREE_FN keyFree; HASH_TABLE_VALUE_FREE_FN valueFree; }; typedef struct _wHashTable wHashTable; WINPR_API int HashTable_Count(wHashTable* table); WINPR_API int HashTable_Add(wHashTable* table, void* key, void* value); WINPR_API BOOL HashTable_Remove(wHashTable* table, void* key); WINPR_API void HashTable_Clear(wHashTable* table); WINPR_API BOOL HashTable_Contains(wHashTable* table, void* key); WINPR_API BOOL HashTable_ContainsKey(wHashTable* table, void* key); WINPR_API BOOL HashTable_ContainsValue(wHashTable* table, void* value); WINPR_API void* HashTable_GetItemValue(wHashTable* table, void* key); WINPR_API BOOL HashTable_SetItemValue(wHashTable* table, void* key, void* value); WINPR_API int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys); WINPR_API UINT32 HashTable_PointerHash(void* pointer); WINPR_API BOOL HashTable_PointerCompare(void* pointer1, void* pointer2); WINPR_API UINT32 HashTable_StringHash(void* key); WINPR_API BOOL HashTable_StringCompare(void* string1, void* string2); WINPR_API void* HashTable_StringClone(void* str); WINPR_API void HashTable_StringFree(void* str); WINPR_API wHashTable* HashTable_New(BOOL synchronized); WINPR_API void HashTable_Free(wHashTable* table); /* BufferPool */ struct _wBufferPoolItem { int size; void* buffer; }; typedef struct _wBufferPoolItem wBufferPoolItem; struct _wBufferPool { int fixedSize; DWORD alignment; BOOL synchronized; CRITICAL_SECTION lock; int size; int capacity; void** array; int aSize; int aCapacity; wBufferPoolItem* aArray; int uSize; int uCapacity; wBufferPoolItem* uArray; }; typedef struct _wBufferPool wBufferPool; WINPR_API int BufferPool_GetPoolSize(wBufferPool* pool); WINPR_API int BufferPool_GetBufferSize(wBufferPool* pool, void* buffer); WINPR_API void* BufferPool_Take(wBufferPool* pool, int bufferSize); WINPR_API BOOL BufferPool_Return(wBufferPool* pool, void* buffer); WINPR_API void BufferPool_Clear(wBufferPool* pool); WINPR_API wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment); WINPR_API void BufferPool_Free(wBufferPool* pool); /* ObjectPool */ struct _wObjectPool { int size; int capacity; void** array; CRITICAL_SECTION lock; wObject object; BOOL synchronized; }; typedef struct _wObjectPool wObjectPool; WINPR_API void* ObjectPool_Take(wObjectPool* pool); WINPR_API void ObjectPool_Return(wObjectPool* pool, void* obj); WINPR_API void ObjectPool_Clear(wObjectPool* pool); #define ObjectPool_Object(_pool) (&_pool->object) WINPR_API wObjectPool* ObjectPool_New(BOOL synchronized); WINPR_API void ObjectPool_Free(wObjectPool* pool); /* Message Queue */ typedef struct _wMessage wMessage; typedef void (*MESSAGE_FREE_FN)(wMessage* message); struct _wMessage { UINT32 id; void* context; void* wParam; void* lParam; UINT64 time; MESSAGE_FREE_FN Free; }; struct _wMessageQueue { int head; int tail; int size; int capacity; wMessage* array; CRITICAL_SECTION lock; HANDLE event; wObject object; }; typedef struct _wMessageQueue wMessageQueue; #define WMQ_QUIT 0xFFFFFFFF WINPR_API HANDLE MessageQueue_Event(wMessageQueue* queue); WINPR_API BOOL MessageQueue_Wait(wMessageQueue* queue); WINPR_API int MessageQueue_Size(wMessageQueue* queue); WINPR_API BOOL MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message); WINPR_API BOOL MessageQueue_Post(wMessageQueue* queue, void* context, UINT32 type, void* wParam, void* lParam); WINPR_API BOOL MessageQueue_PostQuit(wMessageQueue* queue, int nExitCode); WINPR_API int MessageQueue_Get(wMessageQueue* queue, wMessage* message); WINPR_API int MessageQueue_Peek(wMessageQueue* queue, wMessage* message, BOOL remove); /*! \brief Clears all elements in a message queue. * * \note If dynamically allocated data is part of the messages, * a custom cleanup handler must be passed in the 'callback' * argument for MessageQueue_New. * * \param queue The queue to clear. * * \return 0 in case of success or a error code otherwise. */ WINPR_API int MessageQueue_Clear(wMessageQueue* queue); /*! \brief Creates a new message queue. * If 'callback' is null, no custom cleanup will be done * on message queue deallocation. * If the 'callback' argument contains valid uninit or * free functions those will be called by * 'MessageQueue_Clear'. * * \param callback a pointer to custom initialization / cleanup functions. * Can be NULL if not used. * * \return A pointer to a newly allocated MessageQueue or NULL. */ WINPR_API wMessageQueue* MessageQueue_New(const wObject* callback); /*! \brief Frees resources allocated by a message queue. * This function will only free resources allocated * internally. * * \note Empty the queue before calling this function with * 'MessageQueue_Clear', 'MessageQueue_Get' or * 'MessageQueue_Peek' to free all resources allocated * by the message contained. * * \param queue A pointer to the queue to be freed. */ WINPR_API void MessageQueue_Free(wMessageQueue* queue); /* Message Pipe */ struct _wMessagePipe { wMessageQueue* In; wMessageQueue* Out; }; typedef struct _wMessagePipe wMessagePipe; WINPR_API void MessagePipe_PostQuit(wMessagePipe* pipe, int nExitCode); WINPR_API wMessagePipe* MessagePipe_New(void); WINPR_API void MessagePipe_Free(wMessagePipe* pipe); /* Publisher/Subscriber Pattern */ struct _wEventArgs { DWORD Size; const char* Sender; }; typedef struct _wEventArgs wEventArgs; typedef void (*pEventHandler)(void* context, wEventArgs* e); #define MAX_EVENT_HANDLERS 32 struct _wEventType { const char* EventName; wEventArgs EventArgs; int EventHandlerCount; pEventHandler EventHandlers[MAX_EVENT_HANDLERS]; }; typedef struct _wEventType wEventType; #define EventArgsInit(_event_args, _sender) \ memset(_event_args, 0, sizeof(*_event_args)); \ ((wEventArgs*)_event_args)->Size = sizeof(*_event_args); \ ((wEventArgs*)_event_args)->Sender = _sender #define DEFINE_EVENT_HANDLER(_name) \ typedef void (*p##_name##EventHandler)(void* context, _name##EventArgs* e) #define DEFINE_EVENT_RAISE(_name) \ static INLINE int PubSub_On##_name(wPubSub* pubSub, void* context, _name##EventArgs* e) \ { \ return PubSub_OnEvent(pubSub, #_name, context, (wEventArgs*)e); \ } #define DEFINE_EVENT_SUBSCRIBE(_name) \ static INLINE int PubSub_Subscribe##_name(wPubSub* pubSub, \ p##_name##EventHandler EventHandler) \ { \ return PubSub_Subscribe(pubSub, #_name, (pEventHandler)EventHandler); \ } #define DEFINE_EVENT_UNSUBSCRIBE(_name) \ static INLINE int PubSub_Unsubscribe##_name(wPubSub* pubSub, \ p##_name##EventHandler EventHandler) \ { \ return PubSub_Unsubscribe(pubSub, #_name, (pEventHandler)EventHandler); \ } #define DEFINE_EVENT_BEGIN(_name) \ typedef struct _##_name##EventArgs \ { \ wEventArgs e; #define DEFINE_EVENT_END(_name) \ } \ _name##EventArgs; \ DEFINE_EVENT_HANDLER(_name); \ DEFINE_EVENT_RAISE(_name) \ DEFINE_EVENT_SUBSCRIBE(_name) \ DEFINE_EVENT_UNSUBSCRIBE(_name) #define DEFINE_EVENT_ENTRY(_name) { #_name, { sizeof(_name##EventArgs), NULL }, 0, { NULL } }, struct _wPubSub { CRITICAL_SECTION lock; BOOL synchronized; int size; int count; wEventType* events; }; typedef struct _wPubSub wPubSub; WINPR_API void PubSub_Lock(wPubSub* pubSub); WINPR_API void PubSub_Unlock(wPubSub* pubSub); WINPR_API wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count); WINPR_API void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, int count); WINPR_API wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName); WINPR_API int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, pEventHandler EventHandler); WINPR_API int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, pEventHandler EventHandler); WINPR_API int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, wEventArgs* e); WINPR_API wPubSub* PubSub_New(BOOL synchronized); WINPR_API void PubSub_Free(wPubSub* pubSub); /* BipBuffer */ struct _wBipBlock { size_t index; size_t size; }; typedef struct _wBipBlock wBipBlock; struct _wBipBuffer { size_t size; BYTE* buffer; size_t pageSize; wBipBlock blockA; wBipBlock blockB; wBipBlock readR; wBipBlock writeR; }; typedef struct _wBipBuffer wBipBuffer; WINPR_API BOOL BipBuffer_Grow(wBipBuffer* bb, size_t size); WINPR_API void BipBuffer_Clear(wBipBuffer* bb); WINPR_API size_t BipBuffer_UsedSize(wBipBuffer* bb); WINPR_API size_t BipBuffer_BufferSize(wBipBuffer* bb); WINPR_API BYTE* BipBuffer_WriteReserve(wBipBuffer* bb, size_t size); WINPR_API BYTE* BipBuffer_WriteTryReserve(wBipBuffer* bb, size_t size, size_t* reserved); WINPR_API void BipBuffer_WriteCommit(wBipBuffer* bb, size_t size); WINPR_API BYTE* BipBuffer_ReadReserve(wBipBuffer* bb, size_t size); WINPR_API BYTE* BipBuffer_ReadTryReserve(wBipBuffer* bb, size_t size, size_t* reserved); WINPR_API void BipBuffer_ReadCommit(wBipBuffer* bb, size_t size); WINPR_API SSIZE_T BipBuffer_Read(wBipBuffer* bb, BYTE* data, size_t size); WINPR_API SSIZE_T BipBuffer_Write(wBipBuffer* bb, const BYTE* data, size_t size); WINPR_API wBipBuffer* BipBuffer_New(size_t size); WINPR_API void BipBuffer_Free(wBipBuffer* bb); #ifdef __cplusplus } #endif #endif /* WINPR_COLLECTIONS_H */