xref: /PHP-8.4/Zend/zend_stack.c (revision bb07e202)
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 void 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 }
32 
zend_stack_push(zend_stack * stack,const void * element)33 ZEND_API int zend_stack_push(zend_stack *stack, const void *element)
34 {
35 	/* We need to allocate more memory */
36 	if (stack->top >= stack->max) {
37 		stack->max += STACK_BLOCK_SIZE;
38 		stack->elements = safe_erealloc(stack->elements, stack->size, stack->max, 0);
39 	}
40 	memcpy(ZEND_STACK_ELEMENT(stack, stack->top), element, stack->size);
41 	return stack->top++;
42 }
43 
44 
zend_stack_top(const zend_stack * stack)45 ZEND_API void *zend_stack_top(const zend_stack *stack)
46 {
47 	if (stack->top > 0) {
48 		return ZEND_STACK_ELEMENT(stack, stack->top - 1);
49 	} else {
50 		return NULL;
51 	}
52 }
53 
54 
zend_stack_del_top(zend_stack * stack)55 ZEND_API void zend_stack_del_top(zend_stack *stack)
56 {
57 	--stack->top;
58 }
59 
60 
zend_stack_int_top(const zend_stack * stack)61 ZEND_API int zend_stack_int_top(const zend_stack *stack)
62 {
63 	int *e = zend_stack_top(stack);
64 	if (e) {
65 		return *e;
66 	} else {
67 		return FAILURE;
68 	}
69 }
70 
71 
zend_stack_is_empty(const zend_stack * stack)72 ZEND_API bool zend_stack_is_empty(const zend_stack *stack)
73 {
74 	return stack->top == 0;
75 }
76 
77 
zend_stack_destroy(zend_stack * stack)78 ZEND_API void zend_stack_destroy(zend_stack *stack)
79 {
80 	if (stack->elements) {
81 		efree(stack->elements);
82 		stack->elements = NULL;
83 	}
84 }
85 
86 
zend_stack_base(const zend_stack * stack)87 ZEND_API void *zend_stack_base(const zend_stack *stack)
88 {
89 	return stack->elements;
90 }
91 
92 
zend_stack_count(const zend_stack * stack)93 ZEND_API int zend_stack_count(const zend_stack *stack)
94 {
95 	return stack->top;
96 }
97 
98 
zend_stack_apply(zend_stack * stack,int type,int (* apply_function)(void * element))99 ZEND_API void zend_stack_apply(zend_stack *stack, int type, int (*apply_function)(void *element))
100 {
101 	int i;
102 
103 	switch (type) {
104 		case ZEND_STACK_APPLY_TOPDOWN:
105 			for (i=stack->top-1; i>=0; i--) {
106 				if (apply_function(ZEND_STACK_ELEMENT(stack, i))) {
107 					break;
108 				}
109 			}
110 			break;
111 		case ZEND_STACK_APPLY_BOTTOMUP:
112 			for (i=0; i<stack->top; i++) {
113 				if (apply_function(ZEND_STACK_ELEMENT(stack, i))) {
114 					break;
115 				}
116 			}
117 			break;
118 	}
119 }
120 
121 
zend_stack_apply_with_argument(zend_stack * stack,zend_stack_apply_direction type,int (* apply_function)(void * element,void * arg),void * arg)122 ZEND_API void zend_stack_apply_with_argument(zend_stack *stack, zend_stack_apply_direction type, int (*apply_function)(void *element, void *arg), void *arg)
123 {
124 	int i;
125 
126 	switch (type) {
127 		case ZEND_STACK_APPLY_TOPDOWN:
128 			for (i=stack->top-1; i>=0; i--) {
129 				if (apply_function(ZEND_STACK_ELEMENT(stack, i), arg)) {
130 					break;
131 				}
132 			}
133 			break;
134 		case ZEND_STACK_APPLY_BOTTOMUP:
135 			for (i=0; i<stack->top; i++) {
136 				if (apply_function(ZEND_STACK_ELEMENT(stack, i), arg)) {
137 					break;
138 				}
139 			}
140 			break;
141 	}
142 }
143 
zend_stack_clean(zend_stack * stack,void (* func)(void *),bool free_elements)144 ZEND_API void zend_stack_clean(zend_stack *stack, void (*func)(void *), bool free_elements)
145 {
146 	int i;
147 
148 	if (func) {
149 		for (i = 0; i < stack->top; i++) {
150 			func(ZEND_STACK_ELEMENT(stack, i));
151 		}
152 	}
153 	if (free_elements) {
154 		if (stack->elements) {
155 			efree(stack->elements);
156 			stack->elements = NULL;
157 		}
158 		stack->top = stack->max = 0;
159 	}
160 }
161