xref: /PHP-7.4/Zend/zend_stack.c (revision 92ac598a)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    +----------------------------------------------------------------------+
18 */
19 
20 #include "zend.h"
21 #include "zend_stack.h"
22 
23 #define ZEND_STACK_ELEMENT(stack, n) ((void *)((char *) (stack)->elements + (stack)->size * (n)))
24 
zend_stack_init(zend_stack * stack,int size)25 ZEND_API int zend_stack_init(zend_stack *stack, int size)
26 {
27 	stack->size = size;
28 	stack->top = 0;
29 	stack->max = 0;
30 	stack->elements = NULL;
31 	return SUCCESS;
32 }
33 
zend_stack_push(zend_stack * stack,const void * element)34 ZEND_API int zend_stack_push(zend_stack *stack, const void *element)
35 {
36 	/* We need to allocate more memory */
37 	if (stack->top >= stack->max) {
38 		stack->max += STACK_BLOCK_SIZE;
39 		stack->elements = safe_erealloc(stack->elements, stack->size, stack->max, 0);
40 	}
41 	memcpy(ZEND_STACK_ELEMENT(stack, stack->top), element, stack->size);
42 	return stack->top++;
43 }
44 
45 
zend_stack_top(const zend_stack * stack)46 ZEND_API void *zend_stack_top(const zend_stack *stack)
47 {
48 	if (stack->top > 0) {
49 		return ZEND_STACK_ELEMENT(stack, stack->top - 1);
50 	} else {
51 		return NULL;
52 	}
53 }
54 
55 
zend_stack_del_top(zend_stack * stack)56 ZEND_API int zend_stack_del_top(zend_stack *stack)
57 {
58 	--stack->top;
59 	return SUCCESS;
60 }
61 
62 
zend_stack_int_top(const zend_stack * stack)63 ZEND_API int zend_stack_int_top(const zend_stack *stack)
64 {
65 	int *e = zend_stack_top(stack);
66 	if (e) {
67 		return *e;
68 	} else {
69 		return FAILURE;
70 	}
71 }
72 
73 
zend_stack_is_empty(const zend_stack * stack)74 ZEND_API int zend_stack_is_empty(const zend_stack *stack)
75 {
76 	return stack->top == 0;
77 }
78 
79 
zend_stack_destroy(zend_stack * stack)80 ZEND_API int zend_stack_destroy(zend_stack *stack)
81 {
82 	if (stack->elements) {
83 		efree(stack->elements);
84 		stack->elements = NULL;
85 	}
86 
87 	return SUCCESS;
88 }
89 
90 
zend_stack_base(const zend_stack * stack)91 ZEND_API void *zend_stack_base(const zend_stack *stack)
92 {
93 	return stack->elements;
94 }
95 
96 
zend_stack_count(const zend_stack * stack)97 ZEND_API int zend_stack_count(const zend_stack *stack)
98 {
99 	return stack->top;
100 }
101 
102 
zend_stack_apply(zend_stack * stack,int type,int (* apply_function)(void * element))103 ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function)(void *element))
104 {
105 	int i;
106 
107 	switch (type) {
108 		case ZEND_STACK_APPLY_TOPDOWN:
109 			for (i=stack->top-1; i>=0; i--) {
110 				if (apply_function(ZEND_STACK_ELEMENT(stack, i))) {
111 					break;
112 				}
113 			}
114 			break;
115 		case ZEND_STACK_APPLY_BOTTOMUP:
116 			for (i=0; i<stack->top; i++) {
117 				if (apply_function(ZEND_STACK_ELEMENT(stack, i))) {
118 					break;
119 				}
120 			}
121 			break;
122 	}
123 }
124 
125 
zend_stack_apply_with_argument(zend_stack * stack,int type,int (* apply_function)(void * element,void * arg),void * arg)126 ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, int type, int (*apply_function)(void *element, void *arg), void *arg)
127 {
128 	int i;
129 
130 	switch (type) {
131 		case ZEND_STACK_APPLY_TOPDOWN:
132 			for (i=stack->top-1; i>=0; i--) {
133 				if (apply_function(ZEND_STACK_ELEMENT(stack, i), arg)) {
134 					break;
135 				}
136 			}
137 			break;
138 		case ZEND_STACK_APPLY_BOTTOMUP:
139 			for (i=0; i<stack->top; i++) {
140 				if (apply_function(ZEND_STACK_ELEMENT(stack, i), arg)) {
141 					break;
142 				}
143 			}
144 			break;
145 	}
146 }
147 
zend_stack_clean(zend_stack * stack,void (* func)(void *),zend_bool free_elements)148 ZEND_API void zend_stack_clean(zend_stack *stack, void (*func)(void *), zend_bool free_elements)
149 {
150 	int i;
151 
152 	if (func) {
153 		for (i = 0; i < stack->top; i++) {
154 			func(ZEND_STACK_ELEMENT(stack, i));
155 		}
156 	}
157 	if (free_elements) {
158 		if (stack->elements) {
159 			efree(stack->elements);
160 			stack->elements = NULL;
161 		}
162 		stack->top = stack->max = 0;
163 	}
164 }
165