1 /**
2  * WinPR: Windows Portable Runtime
3  * System.Collections.Stack
4  *
5  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <winpr/collections.h>
25 
26 /**
27  * C equivalent of the C# Stack Class:
28  * http://msdn.microsoft.com/en-us/library/system.collections.stack.aspx
29  */
30 
31 /**
32  * Properties
33  */
34 
35 /**
36  * Gets the number of elements contained in the Stack.
37  */
38 
Stack_Count(wStack * stack)39 int Stack_Count(wStack* stack)
40 {
41 	int ret;
42 
43 	if (stack->synchronized)
44 		EnterCriticalSection(&stack->lock);
45 
46 	ret = stack->size;
47 
48 	if (stack->synchronized)
49 		LeaveCriticalSection(&stack->lock);
50 
51 	return ret;
52 }
53 
54 /**
55  * Gets a value indicating whether access to the Stack is synchronized (thread safe).
56  */
57 
Stack_IsSynchronized(wStack * stack)58 BOOL Stack_IsSynchronized(wStack* stack)
59 {
60 	return stack->synchronized;
61 }
62 
63 /**
64  * Methods
65  */
66 
67 /**
68  * Removes all objects from the Stack.
69  */
70 
Stack_Clear(wStack * stack)71 void Stack_Clear(wStack* stack)
72 {
73 	int index;
74 
75 	if (stack->synchronized)
76 		EnterCriticalSection(&stack->lock);
77 
78 	for (index = 0; index < stack->size; index++)
79 	{
80 		if (stack->object.fnObjectFree)
81 			stack->object.fnObjectFree(stack->array[index]);
82 
83 		stack->array[index] = NULL;
84 	}
85 
86 	stack->size = 0;
87 
88 	if (stack->synchronized)
89 		LeaveCriticalSection(&stack->lock);
90 }
91 
92 /**
93  * Determines whether an element is in the Stack.
94  */
95 
Stack_Contains(wStack * stack,void * obj)96 BOOL Stack_Contains(wStack* stack, void* obj)
97 {
98 	int i;
99 	BOOL found = FALSE;
100 
101 	if (stack->synchronized)
102 		EnterCriticalSection(&stack->lock);
103 
104 	for (i = 0; i < stack->size; i++)
105 	{
106 		if (stack->object.fnObjectEquals(stack->array[i], obj))
107 		{
108 			found = TRUE;
109 			break;
110 		}
111 	}
112 
113 	if (stack->synchronized)
114 		LeaveCriticalSection(&stack->lock);
115 
116 	return found;
117 }
118 
119 /**
120  * Inserts an object at the top of the Stack.
121  */
122 
Stack_Push(wStack * stack,void * obj)123 void Stack_Push(wStack* stack, void* obj)
124 {
125 	if (stack->synchronized)
126 		EnterCriticalSection(&stack->lock);
127 
128 	if ((stack->size + 1) >= stack->capacity)
129 	{
130 		int new_cap;
131 		void** new_arr;
132 		new_cap = stack->capacity * 2;
133 		new_arr = (void**)realloc(stack->array, sizeof(void*) * new_cap);
134 
135 		if (!new_arr)
136 			return;
137 
138 		stack->array = new_arr;
139 		stack->capacity = new_cap;
140 	}
141 
142 	stack->array[(stack->size)++] = obj;
143 
144 	if (stack->synchronized)
145 		LeaveCriticalSection(&stack->lock);
146 }
147 
148 /**
149  * Removes and returns the object at the top of the Stack.
150  */
151 
Stack_Pop(wStack * stack)152 void* Stack_Pop(wStack* stack)
153 {
154 	void* obj = NULL;
155 
156 	if (stack->synchronized)
157 		EnterCriticalSection(&stack->lock);
158 
159 	if (stack->size > 0)
160 		obj = stack->array[--(stack->size)];
161 
162 	if (stack->synchronized)
163 		LeaveCriticalSection(&stack->lock);
164 
165 	return obj;
166 }
167 
168 /**
169  * Returns the object at the top of the Stack without removing it.
170  */
171 
Stack_Peek(wStack * stack)172 void* Stack_Peek(wStack* stack)
173 {
174 	void* obj = NULL;
175 
176 	if (stack->synchronized)
177 		EnterCriticalSection(&stack->lock);
178 
179 	if (stack->size > 0)
180 		obj = stack->array[stack->size - 1];
181 
182 	if (stack->synchronized)
183 		LeaveCriticalSection(&stack->lock);
184 
185 	return obj;
186 }
187 
default_stack_equals(const void * obj1,const void * obj2)188 static BOOL default_stack_equals(const void* obj1, const void* obj2)
189 {
190 	return (obj1 == obj2);
191 }
192 
193 /**
194  * Construction, Destruction
195  */
196 
Stack_New(BOOL synchronized)197 wStack* Stack_New(BOOL synchronized)
198 {
199 	wStack* stack = NULL;
200 	stack = (wStack*)calloc(1, sizeof(wStack));
201 
202 	if (!stack)
203 		return NULL;
204 
205 	stack->object.fnObjectEquals = default_stack_equals;
206 	stack->synchronized = synchronized;
207 	stack->capacity = 32;
208 	stack->array = (void**)calloc(stack->capacity, sizeof(void*));
209 
210 	if (!stack->array)
211 		goto out_free;
212 
213 	if (stack->synchronized && !InitializeCriticalSectionAndSpinCount(&stack->lock, 4000))
214 		goto out_free_array;
215 
216 	return stack;
217 out_free_array:
218 	free(stack->array);
219 out_free:
220 	free(stack);
221 	return NULL;
222 }
223 
Stack_Free(wStack * stack)224 void Stack_Free(wStack* stack)
225 {
226 	if (stack)
227 	{
228 		if (stack->synchronized)
229 			DeleteCriticalSection(&stack->lock);
230 
231 		free(stack->array);
232 		free(stack);
233 	}
234 }
235