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