Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 1 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
| 2 | * All rights reserved. |
| 3 | * |
| 4 | * This package is an SSL implementation written |
| 5 | * by Eric Young (eay@cryptsoft.com). |
| 6 | * The implementation was written so as to conform with Netscapes SSL. |
| 7 | * |
| 8 | * This library is free for commercial and non-commercial use as long as |
| 9 | * the following conditions are aheared to. The following conditions |
| 10 | * apply to all code found in this distribution, be it the RC4, RSA, |
| 11 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation |
| 12 | * included with this distribution is covered by the same copyright terms |
| 13 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). |
| 14 | * |
| 15 | * Copyright remains Eric Young's, and as such any Copyright notices in |
| 16 | * the code are not to be removed. |
| 17 | * If this package is used in a product, Eric Young should be given attribution |
| 18 | * as the author of the parts of the library used. |
| 19 | * This can be in the form of a textual message at program startup or |
| 20 | * in documentation (online or textual) provided with the package. |
| 21 | * |
| 22 | * Redistribution and use in source and binary forms, with or without |
| 23 | * modification, are permitted provided that the following conditions |
| 24 | * are met: |
| 25 | * 1. Redistributions of source code must retain the copyright |
| 26 | * notice, this list of conditions and the following disclaimer. |
| 27 | * 2. Redistributions in binary form must reproduce the above copyright |
| 28 | * notice, this list of conditions and the following disclaimer in the |
| 29 | * documentation and/or other materials provided with the distribution. |
| 30 | * 3. All advertising materials mentioning features or use of this software |
| 31 | * must display the following acknowledgement: |
| 32 | * "This product includes cryptographic software written by |
| 33 | * Eric Young (eay@cryptsoft.com)" |
| 34 | * The word 'cryptographic' can be left out if the rouines from the library |
| 35 | * being used are not cryptographic related :-). |
| 36 | * 4. If you include any Windows specific code (or a derivative thereof) from |
| 37 | * the apps directory (application code) you must include an acknowledgement: |
| 38 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
| 39 | * |
| 40 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
| 41 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 42 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 43 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 44 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 45 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 46 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 47 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 48 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 49 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 50 | * SUCH DAMAGE. |
| 51 | * |
| 52 | * The licence and distribution terms for any publically available version or |
| 53 | * derivative of this code cannot be changed. i.e. this code cannot simply be |
| 54 | * copied and put under another distribution licence |
| 55 | * [including the GNU Public Licence.] */ |
| 56 | |
| 57 | #ifndef OPENSSL_HEADER_STACK_H |
| 58 | #define OPENSSL_HEADER_STACK_H |
| 59 | |
| 60 | #include <openssl/base.h> |
| 61 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 62 | #if defined(__cplusplus) |
| 63 | extern "C" { |
| 64 | #endif |
| 65 | |
| 66 | |
David Benjamin | 4512b79 | 2017-08-18 19:21:50 -0400 | [diff] [blame] | 67 | // A stack, in OpenSSL, is an array of pointers. They are the most commonly |
| 68 | // used collection object. |
| 69 | // |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 70 | // This file defines macros for type-safe use of the stack functions. A stack |
| 71 | // type is named like |STACK_OF(FOO)| and is accessed with functions named |
| 72 | // like |sk_FOO_*|. Note the stack will typically contain /pointers/ to |FOO|. |
David Benjamin | 4512b79 | 2017-08-18 19:21:50 -0400 | [diff] [blame] | 73 | // |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 74 | // The |DECLARE_STACK_OF| macro makes |STACK_OF(FOO)| available, and |
| 75 | // |DEFINE_STACK_OF| makes the corresponding functions available. |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 76 | |
| 77 | |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 78 | // Defining stacks. |
| 79 | |
| 80 | // STACK_OF expands to the stack type for |type|. |
| 81 | #define STACK_OF(type) struct stack_st_##type |
| 82 | |
| 83 | // DECLARE_STACK_OF declares the |STACK_OF(type)| type. It does not make the |
| 84 | // corresponding |sk_type_*| functions available. This macro should be used in |
| 85 | // files which only need the type. |
| 86 | #define DECLARE_STACK_OF(type) STACK_OF(type); |
| 87 | |
| 88 | // DEFINE_NAMED_STACK_OF defines |STACK_OF(name)| to be a stack whose elements |
| 89 | // are |type| *. This macro makes the |sk_name_*| functions available. |
| 90 | // |
| 91 | // It is not necessary to use |DECLARE_STACK_OF| in files which use this macro. |
| 92 | #define DEFINE_NAMED_STACK_OF(name, type) \ |
| 93 | BORINGSSL_DEFINE_STACK_OF_IMPL(name, type *, const type *) \ |
| 94 | BORINGSSL_DEFINE_STACK_TRAITS(name, type, false) |
| 95 | |
| 96 | // DEFINE_STACK_OF defines |STACK_OF(type)| to be a stack whose elements are |
| 97 | // |type| *. This macro makes the |sk_type_*| functions available. |
| 98 | // |
| 99 | // It is not necessary to use |DECLARE_STACK_OF| in files which use this macro. |
| 100 | #define DEFINE_STACK_OF(type) DEFINE_NAMED_STACK_OF(type, type) |
| 101 | |
| 102 | // DEFINE_CONST_STACK_OF defines |STACK_OF(type)| to be a stack whose elements |
| 103 | // are const |type| *. This macro makes the |sk_type_*| functions available. |
| 104 | // |
| 105 | // It is not necessary to use |DECLARE_STACK_OF| in files which use this macro. |
| 106 | #define DEFINE_CONST_STACK_OF(type) \ |
| 107 | BORINGSSL_DEFINE_STACK_OF_IMPL(type, const type *, const type *) \ |
| 108 | BORINGSSL_DEFINE_STACK_TRAITS(type, const type, true) |
| 109 | |
| 110 | |
| 111 | // Using stacks. |
| 112 | // |
| 113 | // After the |DEFINE_STACK_OF| macro is used, the following functions are |
| 114 | // available. |
| 115 | |
| 116 | #if 0 // Sample |
| 117 | |
| 118 | // sk_SAMPLE_free_func is a callback to free an element in a stack. |
| 119 | typedef void (*sk_SAMPLE_free_func)(SAMPLE *); |
| 120 | |
| 121 | // sk_SAMPLE_copy_func is a callback to copy an element in a stack. It should |
| 122 | // return the copy or NULL on error. |
David Benjamin | df8a55b | 2023-01-04 15:52:36 -0800 | [diff] [blame] | 123 | typedef SAMPLE *(*sk_SAMPLE_copy_func)(const SAMPLE *); |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 124 | |
| 125 | // sk_SAMPLE_cmp_func is a callback to compare |*a| to |*b|. It should return a |
| 126 | // value < 0, 0, or > 0 if |*a| is less than, equal to, or greater than |*b|, |
| 127 | // respectively. Note the extra indirection - the function is given a pointer |
| 128 | // to a pointer to the element. This is the |qsort|/|bsearch| comparison |
| 129 | // function applied to an array of |SAMPLE*|. |
David Benjamin | af0739f | 2023-01-09 10:03:02 -0800 | [diff] [blame] | 130 | typedef int (*sk_SAMPLE_cmp_func)(const SAMPLE *const *a, |
| 131 | const SAMPLE *const *b); |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 132 | |
| 133 | // sk_SAMPLE_new creates a new, empty stack with the given comparison function, |
| 134 | // which may be NULL. It returns the new stack or NULL on allocation failure. |
| 135 | STACK_OF(SAMPLE) *sk_SAMPLE_new(sk_SAMPLE_cmp_func comp); |
| 136 | |
| 137 | // sk_SAMPLE_new_null creates a new, empty stack. It returns the new stack or |
| 138 | // NULL on allocation failure. |
| 139 | STACK_OF(SAMPLE) *sk_SAMPLE_new_null(void); |
| 140 | |
David Benjamin | 8c7e925 | 2023-05-23 11:45:09 -0400 | [diff] [blame] | 141 | // sk_SAMPLE_num returns the number of elements in |sk|. It is safe to cast this |
David Benjamin | 821fe33 | 2024-03-22 13:16:03 +1000 | [diff] [blame] | 142 | // value to |int|. |sk| is guaranteed to have at most |INT_MAX| elements. If |
| 143 | // |sk| is NULL, it is treated as the empty list and this function returns zero. |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 144 | size_t sk_SAMPLE_num(const STACK_OF(SAMPLE) *sk); |
| 145 | |
| 146 | // sk_SAMPLE_zero resets |sk| to the empty state but does nothing to free the |
| 147 | // individual elements themselves. |
| 148 | void sk_SAMPLE_zero(STACK_OF(SAMPLE) *sk); |
| 149 | |
| 150 | // sk_SAMPLE_value returns the |i|th pointer in |sk|, or NULL if |i| is out of |
David Benjamin | 821fe33 | 2024-03-22 13:16:03 +1000 | [diff] [blame] | 151 | // range. If |sk| is NULL, it is treated as an empty list and the function |
| 152 | // returns NULL. |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 153 | SAMPLE *sk_SAMPLE_value(const STACK_OF(SAMPLE) *sk, size_t i); |
| 154 | |
| 155 | // sk_SAMPLE_set sets the |i|th pointer in |sk| to |p| and returns |p|. If |i| |
| 156 | // is out of range, it returns NULL. |
| 157 | SAMPLE *sk_SAMPLE_set(STACK_OF(SAMPLE) *sk, size_t i, SAMPLE *p); |
| 158 | |
| 159 | // sk_SAMPLE_free frees |sk|, but does nothing to free the individual elements. |
| 160 | // Use |sk_SAMPLE_pop_free| to also free the elements. |
| 161 | void sk_SAMPLE_free(STACK_OF(SAMPLE) *sk); |
| 162 | |
| 163 | // sk_SAMPLE_pop_free calls |free_func| on each element in |sk| and then |
| 164 | // frees the stack itself. |
| 165 | void sk_SAMPLE_pop_free(STACK_OF(SAMPLE) *sk, sk_SAMPLE_free_func free_func); |
| 166 | |
| 167 | // sk_SAMPLE_insert inserts |p| into the stack at index |where|, moving existing |
| 168 | // elements if needed. It returns the length of the new stack, or zero on |
| 169 | // error. |
| 170 | size_t sk_SAMPLE_insert(STACK_OF(SAMPLE) *sk, SAMPLE *p, size_t where); |
| 171 | |
| 172 | // sk_SAMPLE_delete removes the pointer at index |where|, moving other elements |
| 173 | // down if needed. It returns the removed pointer, or NULL if |where| is out of |
| 174 | // range. |
| 175 | SAMPLE *sk_SAMPLE_delete(STACK_OF(SAMPLE) *sk, size_t where); |
| 176 | |
| 177 | // sk_SAMPLE_delete_ptr removes, at most, one instance of |p| from |sk| based on |
| 178 | // pointer equality. If an instance of |p| is found then |p| is returned, |
| 179 | // otherwise it returns NULL. |
| 180 | SAMPLE *sk_SAMPLE_delete_ptr(STACK_OF(SAMPLE) *sk, const SAMPLE *p); |
| 181 | |
David Benjamin | 49e0791 | 2022-12-26 10:41:26 -0500 | [diff] [blame] | 182 | // sk_SAMPLE_delete_if_func is the callback function for |sk_SAMPLE_delete_if|. |
| 183 | // It should return one to remove |p| and zero to keep it. |
| 184 | typedef int (*sk_SAMPLE_delete_if_func)(SAMPLE *p, void *data); |
| 185 | |
| 186 | // sk_SAMPLE_delete_if calls |func| with each element of |sk| and removes the |
| 187 | // entries where |func| returned one. This function does not free or return |
| 188 | // removed pointers so, if |sk| owns its contents, |func| should release the |
| 189 | // pointers prior to returning one. |
| 190 | void sk_SAMPLE_delete_if(STACK_OF(SAMPLE) *sk, sk_SAMPLE_delete_if_func func, |
| 191 | void *data); |
| 192 | |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 193 | // sk_SAMPLE_find find the first value in |sk| equal to |p|. |sk|'s comparison |
| 194 | // function determines equality, or pointer equality if |sk| has no comparison |
| 195 | // function. |
| 196 | // |
| 197 | // If the stack is sorted (see |sk_SAMPLE_sort|), this function uses a binary |
| 198 | // search. Otherwise it performs a linear search. If it finds a matching |
| 199 | // element, it writes the index to |*out_index| (if |out_index| is not NULL) and |
David Benjamin | 821fe33 | 2024-03-22 13:16:03 +1000 | [diff] [blame] | 200 | // returns one. Otherwise, it returns zero. If |sk| is NULL, it is treated as |
| 201 | // the empty list and the function returns zero. |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 202 | // |
| 203 | // Note this differs from OpenSSL. The type signature is slightly different, and |
| 204 | // OpenSSL's version will implicitly sort |sk| if it has a comparison function |
| 205 | // defined. |
| 206 | int sk_SAMPLE_find(const STACK_OF(SAMPLE) *sk, size_t *out_index, |
| 207 | const SAMPLE *p); |
| 208 | |
| 209 | // sk_SAMPLE_shift removes and returns the first element in |sk|, or NULL if |
| 210 | // |sk| is empty. |
| 211 | SAMPLE *sk_SAMPLE_shift(STACK_OF(SAMPLE) *sk); |
| 212 | |
| 213 | // sk_SAMPLE_push appends |p| to |sk| and returns the length of the new stack, |
| 214 | // or 0 on allocation failure. |
| 215 | size_t sk_SAMPLE_push(STACK_OF(SAMPLE) *sk, SAMPLE *p); |
| 216 | |
| 217 | // sk_SAMPLE_pop removes and returns the last element of |sk|, or NULL if |sk| |
| 218 | // is empty. |
| 219 | SAMPLE *sk_SAMPLE_pop(STACK_OF(SAMPLE) *sk); |
| 220 | |
| 221 | // sk_SAMPLE_dup performs a shallow copy of a stack and returns the new stack, |
| 222 | // or NULL on error. Use |sk_SAMPLE_deep_copy| to also copy the elements. |
| 223 | STACK_OF(SAMPLE) *sk_SAMPLE_dup(const STACK_OF(SAMPLE) *sk); |
| 224 | |
| 225 | // sk_SAMPLE_sort sorts the elements of |sk| into ascending order based on the |
| 226 | // comparison function. The stack maintains a "sorted" flag and sorting an |
| 227 | // already sorted stack is a no-op. |
| 228 | void sk_SAMPLE_sort(STACK_OF(SAMPLE) *sk); |
| 229 | |
| 230 | // sk_SAMPLE_is_sorted returns one if |sk| is known to be sorted and zero |
| 231 | // otherwise. |
| 232 | int sk_SAMPLE_is_sorted(const STACK_OF(SAMPLE) *sk); |
| 233 | |
| 234 | // sk_SAMPLE_set_cmp_func sets the comparison function to be used by |sk| and |
| 235 | // returns the previous one. |
| 236 | sk_SAMPLE_cmp_func sk_SAMPLE_set_cmp_func(STACK_OF(SAMPLE) *sk, |
| 237 | sk_SAMPLE_cmp_func comp); |
| 238 | |
| 239 | // sk_SAMPLE_deep_copy performs a copy of |sk| and of each of the non-NULL |
| 240 | // elements in |sk| by using |copy_func|. If an error occurs, it calls |
| 241 | // |free_func| to free any copies already made and returns NULL. |
| 242 | STACK_OF(SAMPLE) *sk_SAMPLE_deep_copy(const STACK_OF(SAMPLE) *sk, |
| 243 | sk_SAMPLE_copy_func copy_func, |
| 244 | sk_SAMPLE_free_func free_func); |
| 245 | |
| 246 | #endif // Sample |
| 247 | |
| 248 | |
| 249 | // Private functions. |
| 250 | // |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 251 | // The |sk_*| functions generated above are implemented internally using the |
| 252 | // type-erased functions below. Callers should use the typed wrappers instead. |
| 253 | // When using the type-erased functions, callers are responsible for ensuring |
| 254 | // the underlying types are correct. Casting pointers to the wrong types will |
| 255 | // result in memory errors. |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 256 | |
| 257 | // OPENSSL_sk_free_func is a function that frees an element in a stack. Note its |
David Benjamin | fb4e2e0 | 2018-09-23 15:59:51 -0500 | [diff] [blame] | 258 | // actual type is void (*)(T *) for some T. Low-level |sk_*| functions will be |
| 259 | // passed a type-specific wrapper to call it correctly. |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 260 | typedef void (*OPENSSL_sk_free_func)(void *ptr); |
David Benjamin | fb4e2e0 | 2018-09-23 15:59:51 -0500 | [diff] [blame] | 261 | |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 262 | // OPENSSL_sk_copy_func is a function that copies an element in a stack. Note |
David Benjamin | df8a55b | 2023-01-04 15:52:36 -0800 | [diff] [blame] | 263 | // its actual type is T *(*)(const T *) for some T. Low-level |sk_*| functions |
| 264 | // will be passed a type-specific wrapper to call it correctly. |
| 265 | typedef void *(*OPENSSL_sk_copy_func)(const void *ptr); |
David Benjamin | fb4e2e0 | 2018-09-23 15:59:51 -0500 | [diff] [blame] | 266 | |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 267 | // OPENSSL_sk_cmp_func is a comparison function that returns a value < 0, 0 or > |
| 268 | // 0 if |*a| is less than, equal to or greater than |*b|, respectively. Note |
| 269 | // the extra indirection - the function is given a pointer to a pointer to the |
David Benjamin | 4512b79 | 2017-08-18 19:21:50 -0400 | [diff] [blame] | 270 | // element. This differs from the usual qsort/bsearch comparison function. |
David Benjamin | 5248399 | 2018-09-23 16:31:03 -0500 | [diff] [blame] | 271 | // |
David Benjamin | af0739f | 2023-01-09 10:03:02 -0800 | [diff] [blame] | 272 | // Note its actual type is |int (*)(const T *const *a, const T *const *b)|. |
| 273 | // Low-level |sk_*| functions will be passed a type-specific wrapper to call it |
| 274 | // correctly. |
| 275 | typedef int (*OPENSSL_sk_cmp_func)(const void *const *a, const void *const *b); |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 276 | |
David Benjamin | 49e0791 | 2022-12-26 10:41:26 -0500 | [diff] [blame] | 277 | // OPENSSL_sk_delete_if_func is the generic version of |
| 278 | // |sk_SAMPLE_delete_if_func|. |
| 279 | typedef int (*OPENSSL_sk_delete_if_func)(void *obj, void *data); |
| 280 | |
David Benjamin | 167f176 | 2022-06-12 13:47:08 -0400 | [diff] [blame] | 281 | // The following function types call the above type-erased signatures with the |
| 282 | // true types. |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 283 | typedef void (*OPENSSL_sk_call_free_func)(OPENSSL_sk_free_func, void *); |
David Benjamin | df8a55b | 2023-01-04 15:52:36 -0800 | [diff] [blame] | 284 | typedef void *(*OPENSSL_sk_call_copy_func)(OPENSSL_sk_copy_func, const void *); |
David Benjamin | 9d48902 | 2023-06-06 19:34:39 -0400 | [diff] [blame] | 285 | typedef int (*OPENSSL_sk_call_cmp_func)(OPENSSL_sk_cmp_func, const void *, |
| 286 | const void *); |
David Benjamin | 49e0791 | 2022-12-26 10:41:26 -0500 | [diff] [blame] | 287 | typedef int (*OPENSSL_sk_call_delete_if_func)(OPENSSL_sk_delete_if_func, void *, |
| 288 | void *); |
David Benjamin | 167f176 | 2022-06-12 13:47:08 -0400 | [diff] [blame] | 289 | |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 290 | // An OPENSSL_STACK contains an array of pointers. It is not designed to be used |
David Benjamin | 4512b79 | 2017-08-18 19:21:50 -0400 | [diff] [blame] | 291 | // directly, rather the wrapper macros should be used. |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 292 | typedef struct stack_st OPENSSL_STACK; |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 293 | |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 294 | // The following are raw stack functions. They implement the corresponding typed |
| 295 | // |sk_SAMPLE_*| functions generated by |DEFINE_STACK_OF|. Callers shouldn't be |
| 296 | // using them. Rather, callers should use the typed functions. |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 297 | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_new(OPENSSL_sk_cmp_func comp); |
| 298 | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_new_null(void); |
| 299 | OPENSSL_EXPORT size_t OPENSSL_sk_num(const OPENSSL_STACK *sk); |
| 300 | OPENSSL_EXPORT void OPENSSL_sk_zero(OPENSSL_STACK *sk); |
| 301 | OPENSSL_EXPORT void *OPENSSL_sk_value(const OPENSSL_STACK *sk, size_t i); |
| 302 | OPENSSL_EXPORT void *OPENSSL_sk_set(OPENSSL_STACK *sk, size_t i, void *p); |
| 303 | OPENSSL_EXPORT void OPENSSL_sk_free(OPENSSL_STACK *sk); |
| 304 | OPENSSL_EXPORT void OPENSSL_sk_pop_free_ex( |
| 305 | OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func, |
| 306 | OPENSSL_sk_free_func free_func); |
| 307 | OPENSSL_EXPORT size_t OPENSSL_sk_insert(OPENSSL_STACK *sk, void *p, |
| 308 | size_t where); |
| 309 | OPENSSL_EXPORT void *OPENSSL_sk_delete(OPENSSL_STACK *sk, size_t where); |
| 310 | OPENSSL_EXPORT void *OPENSSL_sk_delete_ptr(OPENSSL_STACK *sk, const void *p); |
| 311 | OPENSSL_EXPORT void OPENSSL_sk_delete_if( |
| 312 | OPENSSL_STACK *sk, OPENSSL_sk_call_delete_if_func call_func, |
| 313 | OPENSSL_sk_delete_if_func func, void *data); |
| 314 | OPENSSL_EXPORT int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, |
| 315 | const void *p, |
| 316 | OPENSSL_sk_call_cmp_func call_cmp_func); |
| 317 | OPENSSL_EXPORT void *OPENSSL_sk_shift(OPENSSL_STACK *sk); |
| 318 | OPENSSL_EXPORT size_t OPENSSL_sk_push(OPENSSL_STACK *sk, void *p); |
| 319 | OPENSSL_EXPORT void *OPENSSL_sk_pop(OPENSSL_STACK *sk); |
| 320 | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_dup(const OPENSSL_STACK *sk); |
| 321 | OPENSSL_EXPORT void OPENSSL_sk_sort(OPENSSL_STACK *sk, |
| 322 | OPENSSL_sk_call_cmp_func call_cmp_func); |
| 323 | OPENSSL_EXPORT int OPENSSL_sk_is_sorted(const OPENSSL_STACK *sk); |
| 324 | OPENSSL_EXPORT OPENSSL_sk_cmp_func |
| 325 | OPENSSL_sk_set_cmp_func(OPENSSL_STACK *sk, OPENSSL_sk_cmp_func comp); |
| 326 | OPENSSL_EXPORT OPENSSL_STACK *OPENSSL_sk_deep_copy( |
| 327 | const OPENSSL_STACK *sk, OPENSSL_sk_call_copy_func call_copy_func, |
| 328 | OPENSSL_sk_copy_func copy_func, OPENSSL_sk_call_free_func call_free_func, |
| 329 | OPENSSL_sk_free_func free_func); |
| 330 | |
| 331 | |
| 332 | // Deprecated private functions (hidden). |
| 333 | // |
| 334 | // TODO(crbug.com/boringssl/499): Migrate callers to the typed wrappers, or at |
| 335 | // least the new names and remove the old ones. |
David Benjamin | 690dcdf | 2023-07-11 13:51:59 -0400 | [diff] [blame] | 336 | // |
| 337 | // TODO(b/290792019, b/290785937): Ideally these would at least be inline |
| 338 | // functions, so we do not squat the symbols. |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 339 | |
| 340 | typedef OPENSSL_STACK _STACK; |
| 341 | |
David Benjamin | 690dcdf | 2023-07-11 13:51:59 -0400 | [diff] [blame] | 342 | // The following functions call the corresponding |OPENSSL_sk_*| function. |
David Benjamin | f04fbf5 | 2023-07-20 11:31:07 -0400 | [diff] [blame] | 343 | OPENSSL_EXPORT OPENSSL_DEPRECATED OPENSSL_STACK *sk_new_null(void); |
| 344 | OPENSSL_EXPORT OPENSSL_DEPRECATED size_t sk_num(const OPENSSL_STACK *sk); |
| 345 | OPENSSL_EXPORT OPENSSL_DEPRECATED void *sk_value(const OPENSSL_STACK *sk, |
| 346 | size_t i); |
| 347 | OPENSSL_EXPORT OPENSSL_DEPRECATED void sk_free(OPENSSL_STACK *sk); |
| 348 | OPENSSL_EXPORT OPENSSL_DEPRECATED size_t sk_push(OPENSSL_STACK *sk, void *p); |
| 349 | OPENSSL_EXPORT OPENSSL_DEPRECATED void *sk_pop(OPENSSL_STACK *sk); |
David Benjamin | fb4e2e0 | 2018-09-23 15:59:51 -0500 | [diff] [blame] | 350 | |
David Benjamin | b1ff33d | 2023-07-20 10:53:36 -0400 | [diff] [blame] | 351 | // sk_pop_free_ex calls |OPENSSL_sk_pop_free_ex|. |
| 352 | // |
| 353 | // TODO(b/291994116): Remove this. |
David Benjamin | f04fbf5 | 2023-07-20 11:31:07 -0400 | [diff] [blame] | 354 | OPENSSL_EXPORT OPENSSL_DEPRECATED void sk_pop_free_ex( |
| 355 | OPENSSL_STACK *sk, OPENSSL_sk_call_free_func call_free_func, |
| 356 | OPENSSL_sk_free_func free_func); |
David Benjamin | b1ff33d | 2023-07-20 10:53:36 -0400 | [diff] [blame] | 357 | |
| 358 | // sk_pop_free behaves like |OPENSSL_sk_pop_free_ex| but performs an invalid |
| 359 | // function pointer cast. It exists because some existing callers called |
| 360 | // |sk_pop_free| directly. |
David Benjamin | fb4e2e0 | 2018-09-23 15:59:51 -0500 | [diff] [blame] | 361 | // |
| 362 | // TODO(davidben): Migrate callers to bssl::UniquePtr and remove this. |
David Benjamin | f04fbf5 | 2023-07-20 11:31:07 -0400 | [diff] [blame] | 363 | OPENSSL_EXPORT OPENSSL_DEPRECATED void sk_pop_free( |
| 364 | OPENSSL_STACK *sk, OPENSSL_sk_free_func free_func); |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 365 | |
David Benjamin | 01f8a8c | 2017-04-15 18:12:55 -0400 | [diff] [blame] | 366 | |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 367 | #if !defined(BORINGSSL_NO_CXX) |
| 368 | extern "C++" { |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 369 | BSSL_NAMESPACE_BEGIN |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 370 | namespace internal { |
| 371 | template <typename T> |
| 372 | struct StackTraits {}; |
| 373 | } |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 374 | BSSL_NAMESPACE_END |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 375 | } |
| 376 | |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 377 | #define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) \ |
| 378 | extern "C++" { \ |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 379 | BSSL_NAMESPACE_BEGIN \ |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 380 | namespace internal { \ |
| 381 | template <> \ |
| 382 | struct StackTraits<STACK_OF(name)> { \ |
| 383 | static constexpr bool kIsStack = true; \ |
| 384 | using Type = type; \ |
| 385 | static constexpr bool kIsConst = is_const; \ |
| 386 | }; \ |
| 387 | } \ |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 388 | BSSL_NAMESPACE_END \ |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 389 | } |
| 390 | |
| 391 | #else |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 392 | #define BORINGSSL_DEFINE_STACK_TRAITS(name, type, is_const) |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 393 | #endif |
| 394 | |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 395 | #define BORINGSSL_DEFINE_STACK_OF_IMPL(name, ptrtype, constptrtype) \ |
| 396 | /* We disable MSVC C4191 in this macro, which warns when pointers are cast \ |
| 397 | * to the wrong type. While the cast itself is valid, it is often a bug \ |
| 398 | * because calling it through the cast is UB. However, we never actually \ |
| 399 | * call functions as |OPENSSL_sk_cmp_func|. The type is just a type-erased \ |
| 400 | * function pointer. (C does not guarantee function pointers fit in \ |
| 401 | * |void*|, and GCC will warn on this.) Thus we just disable the false \ |
| 402 | * positive warning. */ \ |
| 403 | OPENSSL_MSVC_PRAGMA(warning(push)) \ |
| 404 | OPENSSL_MSVC_PRAGMA(warning(disable : 4191)) \ |
Brian Ledger | 68c6fd8 | 2024-04-02 15:17:16 -0400 | [diff] [blame] | 405 | OPENSSL_CLANG_PRAGMA("clang diagnostic push") \ |
| 406 | OPENSSL_CLANG_PRAGMA("clang diagnostic ignored \"-Wunknown-warning-option\"") \ |
| 407 | OPENSSL_CLANG_PRAGMA("clang diagnostic ignored \"-Wcast-function-type-strict\"") \ |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 408 | \ |
| 409 | DECLARE_STACK_OF(name) \ |
| 410 | \ |
| 411 | typedef void (*sk_##name##_free_func)(ptrtype); \ |
| 412 | typedef ptrtype (*sk_##name##_copy_func)(constptrtype); \ |
| 413 | typedef int (*sk_##name##_cmp_func)(constptrtype const *, \ |
| 414 | constptrtype const *); \ |
| 415 | typedef int (*sk_##name##_delete_if_func)(ptrtype, void *); \ |
| 416 | \ |
| 417 | OPENSSL_INLINE void sk_##name##_call_free_func( \ |
| 418 | OPENSSL_sk_free_func free_func, void *ptr) { \ |
| 419 | ((sk_##name##_free_func)free_func)((ptrtype)ptr); \ |
| 420 | } \ |
| 421 | \ |
| 422 | OPENSSL_INLINE void *sk_##name##_call_copy_func( \ |
| 423 | OPENSSL_sk_copy_func copy_func, const void *ptr) { \ |
| 424 | return (void *)((sk_##name##_copy_func)copy_func)((constptrtype)ptr); \ |
| 425 | } \ |
| 426 | \ |
| 427 | OPENSSL_INLINE int sk_##name##_call_cmp_func(OPENSSL_sk_cmp_func cmp_func, \ |
David Benjamin | 9d48902 | 2023-06-06 19:34:39 -0400 | [diff] [blame] | 428 | const void *a, const void *b) { \ |
| 429 | constptrtype a_ptr = (constptrtype)a; \ |
| 430 | constptrtype b_ptr = (constptrtype)b; \ |
| 431 | /* |cmp_func| expects an extra layer of pointers to match qsort. */ \ |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 432 | return ((sk_##name##_cmp_func)cmp_func)(&a_ptr, &b_ptr); \ |
| 433 | } \ |
| 434 | \ |
| 435 | OPENSSL_INLINE int sk_##name##_call_delete_if_func( \ |
| 436 | OPENSSL_sk_delete_if_func func, void *obj, void *data) { \ |
| 437 | return ((sk_##name##_delete_if_func)func)((ptrtype)obj, data); \ |
| 438 | } \ |
| 439 | \ |
| 440 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_new(sk_##name##_cmp_func comp) { \ |
| 441 | return (STACK_OF(name) *)OPENSSL_sk_new((OPENSSL_sk_cmp_func)comp); \ |
| 442 | } \ |
| 443 | \ |
| 444 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_new_null(void) { \ |
| 445 | return (STACK_OF(name) *)OPENSSL_sk_new_null(); \ |
| 446 | } \ |
| 447 | \ |
| 448 | OPENSSL_INLINE size_t sk_##name##_num(const STACK_OF(name) *sk) { \ |
| 449 | return OPENSSL_sk_num((const OPENSSL_STACK *)sk); \ |
| 450 | } \ |
| 451 | \ |
| 452 | OPENSSL_INLINE void sk_##name##_zero(STACK_OF(name) *sk) { \ |
| 453 | OPENSSL_sk_zero((OPENSSL_STACK *)sk); \ |
| 454 | } \ |
| 455 | \ |
| 456 | OPENSSL_INLINE ptrtype sk_##name##_value(const STACK_OF(name) *sk, \ |
| 457 | size_t i) { \ |
| 458 | return (ptrtype)OPENSSL_sk_value((const OPENSSL_STACK *)sk, i); \ |
| 459 | } \ |
| 460 | \ |
| 461 | OPENSSL_INLINE ptrtype sk_##name##_set(STACK_OF(name) *sk, size_t i, \ |
| 462 | ptrtype p) { \ |
| 463 | return (ptrtype)OPENSSL_sk_set((OPENSSL_STACK *)sk, i, (void *)p); \ |
| 464 | } \ |
| 465 | \ |
| 466 | OPENSSL_INLINE void sk_##name##_free(STACK_OF(name) *sk) { \ |
| 467 | OPENSSL_sk_free((OPENSSL_STACK *)sk); \ |
| 468 | } \ |
| 469 | \ |
| 470 | OPENSSL_INLINE void sk_##name##_pop_free(STACK_OF(name) *sk, \ |
| 471 | sk_##name##_free_func free_func) { \ |
| 472 | OPENSSL_sk_pop_free_ex((OPENSSL_STACK *)sk, sk_##name##_call_free_func, \ |
| 473 | (OPENSSL_sk_free_func)free_func); \ |
| 474 | } \ |
| 475 | \ |
| 476 | OPENSSL_INLINE size_t sk_##name##_insert(STACK_OF(name) *sk, ptrtype p, \ |
| 477 | size_t where) { \ |
| 478 | return OPENSSL_sk_insert((OPENSSL_STACK *)sk, (void *)p, where); \ |
| 479 | } \ |
| 480 | \ |
| 481 | OPENSSL_INLINE ptrtype sk_##name##_delete(STACK_OF(name) *sk, \ |
| 482 | size_t where) { \ |
| 483 | return (ptrtype)OPENSSL_sk_delete((OPENSSL_STACK *)sk, where); \ |
| 484 | } \ |
| 485 | \ |
| 486 | OPENSSL_INLINE ptrtype sk_##name##_delete_ptr(STACK_OF(name) *sk, \ |
| 487 | constptrtype p) { \ |
| 488 | return (ptrtype)OPENSSL_sk_delete_ptr((OPENSSL_STACK *)sk, \ |
| 489 | (const void *)p); \ |
| 490 | } \ |
| 491 | \ |
| 492 | OPENSSL_INLINE void sk_##name##_delete_if( \ |
| 493 | STACK_OF(name) *sk, sk_##name##_delete_if_func func, void *data) { \ |
| 494 | OPENSSL_sk_delete_if((OPENSSL_STACK *)sk, sk_##name##_call_delete_if_func, \ |
| 495 | (OPENSSL_sk_delete_if_func)func, data); \ |
| 496 | } \ |
| 497 | \ |
| 498 | OPENSSL_INLINE int sk_##name##_find(const STACK_OF(name) *sk, \ |
| 499 | size_t *out_index, constptrtype p) { \ |
| 500 | return OPENSSL_sk_find((const OPENSSL_STACK *)sk, out_index, \ |
| 501 | (const void *)p, sk_##name##_call_cmp_func); \ |
| 502 | } \ |
| 503 | \ |
| 504 | OPENSSL_INLINE ptrtype sk_##name##_shift(STACK_OF(name) *sk) { \ |
| 505 | return (ptrtype)OPENSSL_sk_shift((OPENSSL_STACK *)sk); \ |
| 506 | } \ |
| 507 | \ |
| 508 | OPENSSL_INLINE size_t sk_##name##_push(STACK_OF(name) *sk, ptrtype p) { \ |
| 509 | return OPENSSL_sk_push((OPENSSL_STACK *)sk, (void *)p); \ |
| 510 | } \ |
| 511 | \ |
| 512 | OPENSSL_INLINE ptrtype sk_##name##_pop(STACK_OF(name) *sk) { \ |
| 513 | return (ptrtype)OPENSSL_sk_pop((OPENSSL_STACK *)sk); \ |
| 514 | } \ |
| 515 | \ |
| 516 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_dup(const STACK_OF(name) *sk) { \ |
| 517 | return (STACK_OF(name) *)OPENSSL_sk_dup((const OPENSSL_STACK *)sk); \ |
| 518 | } \ |
| 519 | \ |
| 520 | OPENSSL_INLINE void sk_##name##_sort(STACK_OF(name) *sk) { \ |
| 521 | OPENSSL_sk_sort((OPENSSL_STACK *)sk, sk_##name##_call_cmp_func); \ |
| 522 | } \ |
| 523 | \ |
| 524 | OPENSSL_INLINE int sk_##name##_is_sorted(const STACK_OF(name) *sk) { \ |
| 525 | return OPENSSL_sk_is_sorted((const OPENSSL_STACK *)sk); \ |
| 526 | } \ |
| 527 | \ |
| 528 | OPENSSL_INLINE sk_##name##_cmp_func sk_##name##_set_cmp_func( \ |
| 529 | STACK_OF(name) *sk, sk_##name##_cmp_func comp) { \ |
| 530 | return (sk_##name##_cmp_func)OPENSSL_sk_set_cmp_func( \ |
| 531 | (OPENSSL_STACK *)sk, (OPENSSL_sk_cmp_func)comp); \ |
| 532 | } \ |
| 533 | \ |
| 534 | OPENSSL_INLINE STACK_OF(name) *sk_##name##_deep_copy( \ |
| 535 | const STACK_OF(name) *sk, sk_##name##_copy_func copy_func, \ |
| 536 | sk_##name##_free_func free_func) { \ |
| 537 | return (STACK_OF(name) *)OPENSSL_sk_deep_copy( \ |
| 538 | (const OPENSSL_STACK *)sk, sk_##name##_call_copy_func, \ |
| 539 | (OPENSSL_sk_copy_func)copy_func, sk_##name##_call_free_func, \ |
| 540 | (OPENSSL_sk_free_func)free_func); \ |
| 541 | } \ |
| 542 | \ |
Brian Ledger | 68c6fd8 | 2024-04-02 15:17:16 -0400 | [diff] [blame] | 543 | OPENSSL_CLANG_PRAGMA("clang diagnostic pop") \ |
David Benjamin | 167f176 | 2022-06-12 13:47:08 -0400 | [diff] [blame] | 544 | OPENSSL_MSVC_PRAGMA(warning(pop)) |
David Benjamin | 01f8a8c | 2017-04-15 18:12:55 -0400 | [diff] [blame] | 545 | |
David Benjamin | 35b4a12 | 2018-07-14 17:04:41 -0400 | [diff] [blame] | 546 | |
David Benjamin | 7f857ea | 2022-06-13 11:47:31 -0400 | [diff] [blame] | 547 | // Built-in stacks. |
David Benjamin | 01f8a8c | 2017-04-15 18:12:55 -0400 | [diff] [blame] | 548 | |
David Benjamin | 01f8a8c | 2017-04-15 18:12:55 -0400 | [diff] [blame] | 549 | typedef char *OPENSSL_STRING; |
| 550 | |
| 551 | DEFINE_STACK_OF(void) |
David Benjamin | 1500ad0 | 2022-06-13 12:33:07 -0400 | [diff] [blame] | 552 | DEFINE_NAMED_STACK_OF(OPENSSL_STRING, char) |
David Benjamin | 01f8a8c | 2017-04-15 18:12:55 -0400 | [diff] [blame] | 553 | |
| 554 | |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 555 | #if defined(__cplusplus) |
David Benjamin | 4512b79 | 2017-08-18 19:21:50 -0400 | [diff] [blame] | 556 | } // extern C |
Adam Langley | 95c29f3 | 2014-06-20 12:00:00 -0700 | [diff] [blame] | 557 | #endif |
| 558 | |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 559 | #if !defined(BORINGSSL_NO_CXX) |
| 560 | extern "C++" { |
| 561 | |
| 562 | #include <type_traits> |
| 563 | |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 564 | BSSL_NAMESPACE_BEGIN |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 565 | |
| 566 | namespace internal { |
| 567 | |
| 568 | // Stacks defined with |DEFINE_CONST_STACK_OF| are freed with |sk_free|. |
| 569 | template <typename Stack> |
David Benjamin | 493d5cb | 2022-04-18 17:20:27 -0400 | [diff] [blame] | 570 | struct DeleterImpl<Stack, std::enable_if_t<StackTraits<Stack>::kIsConst>> { |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 571 | static void Free(Stack *sk) { |
| 572 | OPENSSL_sk_free(reinterpret_cast<OPENSSL_STACK *>(sk)); |
| 573 | } |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 574 | }; |
| 575 | |
| 576 | // Stacks defined with |DEFINE_STACK_OF| are freed with |sk_pop_free| and the |
| 577 | // corresponding type's deleter. |
| 578 | template <typename Stack> |
David Benjamin | 493d5cb | 2022-04-18 17:20:27 -0400 | [diff] [blame] | 579 | struct DeleterImpl<Stack, std::enable_if_t<!StackTraits<Stack>::kIsConst>> { |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 580 | static void Free(Stack *sk) { |
David Benjamin | fb4e2e0 | 2018-09-23 15:59:51 -0500 | [diff] [blame] | 581 | // sk_FOO_pop_free is defined by macros and bound by name, so we cannot |
| 582 | // access it from C++ here. |
| 583 | using Type = typename StackTraits<Stack>::Type; |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 584 | OPENSSL_sk_pop_free_ex( |
| 585 | reinterpret_cast<OPENSSL_STACK *>(sk), |
| 586 | [](OPENSSL_sk_free_func /* unused */, void *ptr) { |
| 587 | DeleterImpl<Type>::Free(reinterpret_cast<Type *>(ptr)); |
| 588 | }, |
| 589 | nullptr); |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 590 | } |
| 591 | }; |
| 592 | |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 593 | template <typename Stack> |
| 594 | class StackIteratorImpl { |
| 595 | public: |
| 596 | using Type = typename StackTraits<Stack>::Type; |
| 597 | // Iterators must be default-constructable. |
| 598 | StackIteratorImpl() : sk_(nullptr), idx_(0) {} |
| 599 | StackIteratorImpl(const Stack *sk, size_t idx) : sk_(sk), idx_(idx) {} |
| 600 | |
| 601 | bool operator==(StackIteratorImpl other) const { |
| 602 | return sk_ == other.sk_ && idx_ == other.idx_; |
| 603 | } |
| 604 | bool operator!=(StackIteratorImpl other) const { |
| 605 | return !(*this == other); |
| 606 | } |
| 607 | |
| 608 | Type *operator*() const { |
| 609 | return reinterpret_cast<Type *>( |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 610 | OPENSSL_sk_value(reinterpret_cast<const OPENSSL_STACK *>(sk_), idx_)); |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 611 | } |
| 612 | |
| 613 | StackIteratorImpl &operator++(/* prefix */) { |
| 614 | idx_++; |
| 615 | return *this; |
| 616 | } |
| 617 | |
| 618 | StackIteratorImpl operator++(int /* postfix */) { |
| 619 | StackIteratorImpl copy(*this); |
| 620 | ++(*this); |
| 621 | return copy; |
| 622 | } |
| 623 | |
| 624 | private: |
| 625 | const Stack *sk_; |
| 626 | size_t idx_; |
| 627 | }; |
| 628 | |
| 629 | template <typename Stack> |
David Benjamin | 493d5cb | 2022-04-18 17:20:27 -0400 | [diff] [blame] | 630 | using StackIterator = |
| 631 | std::enable_if_t<StackTraits<Stack>::kIsStack, StackIteratorImpl<Stack>>; |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 632 | |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 633 | } // namespace internal |
| 634 | |
David Benjamin | 6e9321f | 2017-07-25 23:49:58 -0400 | [diff] [blame] | 635 | // PushToStack pushes |elem| to |sk|. It returns true on success and false on |
| 636 | // allocation failure. |
| 637 | template <typename Stack> |
David Benjamin | 493d5cb | 2022-04-18 17:20:27 -0400 | [diff] [blame] | 638 | inline std::enable_if_t<!internal::StackTraits<Stack>::kIsConst, bool> |
| 639 | PushToStack(Stack *sk, |
| 640 | UniquePtr<typename internal::StackTraits<Stack>::Type> elem) { |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 641 | if (!OPENSSL_sk_push(reinterpret_cast<OPENSSL_STACK *>(sk), elem.get())) { |
David Benjamin | 6e9321f | 2017-07-25 23:49:58 -0400 | [diff] [blame] | 642 | return false; |
| 643 | } |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 644 | // OPENSSL_sk_push takes ownership on success. |
David Benjamin | 6e9321f | 2017-07-25 23:49:58 -0400 | [diff] [blame] | 645 | elem.release(); |
| 646 | return true; |
| 647 | } |
| 648 | |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 649 | BSSL_NAMESPACE_END |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 650 | |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 651 | // Define begin() and end() for stack types so C++ range for loops work. |
| 652 | template <typename Stack> |
David Benjamin | a943613 | 2018-09-23 18:36:01 -0500 | [diff] [blame] | 653 | inline bssl::internal::StackIterator<Stack> begin(const Stack *sk) { |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 654 | return bssl::internal::StackIterator<Stack>(sk, 0); |
| 655 | } |
| 656 | |
| 657 | template <typename Stack> |
David Benjamin | a943613 | 2018-09-23 18:36:01 -0500 | [diff] [blame] | 658 | inline bssl::internal::StackIterator<Stack> end(const Stack *sk) { |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 659 | return bssl::internal::StackIterator<Stack>( |
David Benjamin | 99d3c22 | 2023-06-03 23:00:40 -0400 | [diff] [blame] | 660 | sk, OPENSSL_sk_num(reinterpret_cast<const OPENSSL_STACK *>(sk))); |
David Benjamin | ec78383 | 2017-07-25 23:23:03 -0400 | [diff] [blame] | 661 | } |
| 662 | |
David Benjamin | 0121953 | 2017-07-25 22:33:06 -0400 | [diff] [blame] | 663 | } // extern C++ |
| 664 | #endif |
| 665 | |
David Benjamin | 4512b79 | 2017-08-18 19:21:50 -0400 | [diff] [blame] | 666 | #endif // OPENSSL_HEADER_STACK_H |