summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/utils/collections/Stack.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--winpr/libwinpr/utils/collections/Stack.c252
1 files changed, 252 insertions, 0 deletions
diff --git a/winpr/libwinpr/utils/collections/Stack.c b/winpr/libwinpr/utils/collections/Stack.c
new file mode 100644
index 0000000..f8b5c5e
--- /dev/null
+++ b/winpr/libwinpr/utils/collections/Stack.c
@@ -0,0 +1,252 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * System.Collections.Stack
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * 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.
+ */
+
+#include <winpr/config.h>
+
+#include <winpr/collections.h>
+#include <winpr/assert.h>
+
+struct s_wStack
+{
+ size_t size;
+ size_t capacity;
+ void** array;
+ CRITICAL_SECTION lock;
+ BOOL synchronized;
+ wObject object;
+};
+
+/**
+ * C equivalent of the C# Stack Class:
+ * http://msdn.microsoft.com/en-us/library/system.collections.stack.aspx
+ */
+
+/**
+ * Properties
+ */
+
+/**
+ * Gets the number of elements contained in the Stack.
+ */
+
+size_t Stack_Count(wStack* stack)
+{
+ size_t ret = 0;
+ WINPR_ASSERT(stack);
+ if (stack->synchronized)
+ EnterCriticalSection(&stack->lock);
+
+ ret = stack->size;
+
+ if (stack->synchronized)
+ LeaveCriticalSection(&stack->lock);
+
+ return ret;
+}
+
+/**
+ * Gets a value indicating whether access to the Stack is synchronized (thread safe).
+ */
+
+BOOL Stack_IsSynchronized(wStack* stack)
+{
+ WINPR_ASSERT(stack);
+ return stack->synchronized;
+}
+
+wObject* Stack_Object(wStack* stack)
+{
+ WINPR_ASSERT(stack);
+ return &stack->object;
+}
+
+/**
+ * Methods
+ */
+
+/**
+ * Removes all objects from the Stack.
+ */
+
+void Stack_Clear(wStack* stack)
+{
+ WINPR_ASSERT(stack);
+ if (stack->synchronized)
+ EnterCriticalSection(&stack->lock);
+
+ for (size_t index = 0; index < stack->size; index++)
+ {
+ if (stack->object.fnObjectFree)
+ stack->object.fnObjectFree(stack->array[index]);
+
+ stack->array[index] = NULL;
+ }
+
+ stack->size = 0;
+
+ if (stack->synchronized)
+ LeaveCriticalSection(&stack->lock);
+}
+
+/**
+ * Determines whether an element is in the Stack.
+ */
+
+BOOL Stack_Contains(wStack* stack, const void* obj)
+{
+ BOOL found = FALSE;
+
+ WINPR_ASSERT(stack);
+ if (stack->synchronized)
+ EnterCriticalSection(&stack->lock);
+
+ for (size_t i = 0; i < stack->size; i++)
+ {
+ if (stack->object.fnObjectEquals(stack->array[i], obj))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (stack->synchronized)
+ LeaveCriticalSection(&stack->lock);
+
+ return found;
+}
+
+/**
+ * Inserts an object at the top of the Stack.
+ */
+
+void Stack_Push(wStack* stack, void* obj)
+{
+ WINPR_ASSERT(stack);
+ if (stack->synchronized)
+ EnterCriticalSection(&stack->lock);
+
+ if ((stack->size + 1) >= stack->capacity)
+ {
+ const size_t new_cap = stack->capacity * 2;
+ void** new_arr = (void**)realloc(stack->array, sizeof(void*) * new_cap);
+
+ if (!new_arr)
+ goto end;
+
+ stack->array = new_arr;
+ stack->capacity = new_cap;
+ }
+
+ stack->array[(stack->size)++] = obj;
+
+end:
+ if (stack->synchronized)
+ LeaveCriticalSection(&stack->lock);
+}
+
+/**
+ * Removes and returns the object at the top of the Stack.
+ */
+
+void* Stack_Pop(wStack* stack)
+{
+ void* obj = NULL;
+
+ WINPR_ASSERT(stack);
+ if (stack->synchronized)
+ EnterCriticalSection(&stack->lock);
+
+ if (stack->size > 0)
+ obj = stack->array[--(stack->size)];
+
+ if (stack->synchronized)
+ LeaveCriticalSection(&stack->lock);
+
+ return obj;
+}
+
+/**
+ * Returns the object at the top of the Stack without removing it.
+ */
+
+void* Stack_Peek(wStack* stack)
+{
+ void* obj = NULL;
+
+ WINPR_ASSERT(stack);
+ if (stack->synchronized)
+ EnterCriticalSection(&stack->lock);
+
+ if (stack->size > 0)
+ obj = stack->array[stack->size - 1];
+
+ if (stack->synchronized)
+ LeaveCriticalSection(&stack->lock);
+
+ return obj;
+}
+
+static BOOL default_stack_equals(const void* obj1, const void* obj2)
+{
+ return (obj1 == obj2);
+}
+
+/**
+ * Construction, Destruction
+ */
+
+wStack* Stack_New(BOOL synchronized)
+{
+ wStack* stack = NULL;
+ stack = (wStack*)calloc(1, sizeof(wStack));
+
+ if (!stack)
+ return NULL;
+
+ stack->object.fnObjectEquals = default_stack_equals;
+ stack->synchronized = synchronized;
+ stack->capacity = 32;
+ stack->array = (void**)calloc(stack->capacity, sizeof(void*));
+
+ if (!stack->array)
+ goto out_free;
+
+ if (stack->synchronized && !InitializeCriticalSectionAndSpinCount(&stack->lock, 4000))
+ goto out_free;
+
+ return stack;
+out_free:
+ WINPR_PRAGMA_DIAG_PUSH
+ WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
+ Stack_Free(stack);
+ WINPR_PRAGMA_DIAG_POP
+ return NULL;
+}
+
+void Stack_Free(wStack* stack)
+{
+ if (stack)
+ {
+ if (stack->synchronized)
+ DeleteCriticalSection(&stack->lock);
+
+ free(stack->array);
+ free(stack);
+ }
+}