master ohmu/fastfetch-openbsd / src / 3rdparty / sixel / allocator.c
ohmu  ·  2026-10-15
  1/*
  2 * Copyright (c) 2014-2018 Hayaki Saito
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy of
  5 * this software and associated documentation files (the "Software"), to deal in
  6 * the Software without restriction, including without limitation the rights to
  7 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  8 * the Software, and to permit persons to whom the Software is furnished to do so,
  9 * subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in all
 12 * copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 16 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 17 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 18 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 20 */
 21
 22#include "config.h"
 23
 24/* STDC_HEADERS */
 25#include <stdlib.h>
 26
 27#if HAVE_ASSERT_H
 28# include <assert.h>
 29#endif  /* HAVE_ASSERT_H */
 30#if HAVE_SYS_TYPES_H
 31# include <sys/types.h>
 32#endif  /* HAVE_SYS_TYPES_H */
 33#if HAVE_ERRNO_H
 34# include <errno.h>
 35#endif  /* HAVE_ERRNO_H */
 36#if HAVE_MEMORY_H
 37# include <memory.h>
 38#endif  /* HAVE_MEMORY_H */
 39
 40#include "allocator.h"
 41#include "malloc_stub.h"
 42
 43/* create allocator object */
 44SIXELSTATUS
 45sixel_allocator_new(
 46    sixel_allocator_t   /* out */ **ppallocator,  /* allocator object to be created */
 47    sixel_malloc_t      /* in */  fn_malloc,      /* custom malloc() function */
 48    sixel_calloc_t      /* in */  fn_calloc,      /* custom calloc() function */
 49    sixel_realloc_t     /* in */  fn_realloc,     /* custom realloc() function */
 50    sixel_free_t        /* in */  fn_free)        /* custom free() function */
 51{
 52    SIXELSTATUS status = SIXEL_FALSE;
 53
 54    if (ppallocator == NULL) {
 55        sixel_helper_set_additional_message(
 56            "sixel_allocator_new: given argument ppallocator is null.");
 57        status = SIXEL_BAD_ARGUMENT;
 58        goto end;
 59    }
 60
 61    if (fn_malloc == NULL) {
 62        fn_malloc = malloc;
 63    }
 64
 65    if (fn_calloc == NULL) {
 66        fn_calloc = calloc;
 67    }
 68
 69    if (fn_realloc == NULL) {
 70        fn_realloc = realloc;
 71    }
 72
 73    if (fn_free == NULL) {
 74        fn_free = free;
 75    }
 76
 77    *ppallocator = fn_malloc(sizeof(sixel_allocator_t));
 78    if (*ppallocator == NULL) {
 79        sixel_helper_set_additional_message(
 80            "sixel_allocator_new: fn_malloc() failed.");
 81        status = SIXEL_BAD_ALLOCATION;
 82        goto end;
 83    }
 84
 85    (*ppallocator)->ref         = 1;
 86    (*ppallocator)->fn_malloc   = fn_malloc;
 87    (*ppallocator)->fn_calloc   = fn_calloc;
 88    (*ppallocator)->fn_realloc  = fn_realloc;
 89    (*ppallocator)->fn_free     = fn_free;
 90
 91    status = SIXEL_OK;
 92
 93end:
 94    return status;
 95}
 96
 97
 98/* destruct allocator object */
 99static void
100sixel_allocator_destroy(
101    sixel_allocator_t /* in */ *allocator)  /* allocator object to
102                                               be destroyed */
103{
104    /* precondition */
105    assert(allocator);
106    assert(allocator->fn_free);
107
108    allocator->fn_free(allocator);
109}
110
111
112/* increase reference count of allocatort object (thread-unsafe) */
113SIXELAPI void
114sixel_allocator_ref(
115    sixel_allocator_t /* in */ *allocator)  /* allocator object to be
116                                               increment reference counter */
117{
118    /* precondition */
119    assert(allocator);
120
121    /* TODO: be thread safe */
122    ++allocator->ref;
123}
124
125
126/* decrease reference count of output context object (thread-unsafe) */
127SIXELAPI void
128sixel_allocator_unref(
129    sixel_allocator_t /* in */ *allocator)  /* allocator object to be unreference */
130{
131    /* TODO: be thread safe */
132    if (allocator) {
133        assert(allocator->ref > 0);
134        --allocator->ref;
135        if (allocator->ref == 0) {
136            sixel_allocator_destroy(allocator);
137        }
138    }
139}
140
141
142/* call custom malloc() */
143SIXELAPI void *
144sixel_allocator_malloc(
145    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
146    size_t              /* in */ n)           /* allocation size */
147{
148    /* precondition */
149    assert(allocator);
150    assert(allocator->fn_malloc);
151
152    if (n == 0) {
153        sixel_helper_set_additional_message(
154            "sixel_allocator_malloc: called with n == 0");
155        return NULL;
156    }
157
158    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
159        return NULL;
160    }
161
162    return allocator->fn_malloc(n);
163}
164
165
166/* call custom calloc() */
167SIXELAPI void *
168sixel_allocator_calloc(
169    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
170    size_t              /* in */ nelm,        /* number of elements */
171    size_t              /* in */ elsize)      /* size of element */
172{
173    size_t n;
174
175    /* precondition */
176    assert(allocator);
177    assert(allocator->fn_calloc);
178
179    n = nelm * elsize;
180
181    if (n == 0) {
182        sixel_helper_set_additional_message(
183            "sixel_allocator_malloc: called with n == 0");
184        return NULL;
185    }
186
187    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
188        return NULL;
189    }
190
191    return allocator->fn_calloc(nelm, elsize);
192}
193
194
195/* call custom realloc() */
196SIXELAPI void *
197sixel_allocator_realloc(
198    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
199    void                /* in */ *p,          /* existing buffer to be re-allocated */
200    size_t              /* in */ n)           /* re-allocation size */
201{
202    /* precondition */
203    assert(allocator);
204    assert(allocator->fn_realloc);
205
206    if (n == 0) {
207        sixel_helper_set_additional_message(
208            "sixel_allocator_malloc: called with n == 0");
209        return NULL;
210    }
211
212    if (n > SIXEL_ALLOCATE_BYTES_MAX) {
213        return NULL;
214    }
215
216    return allocator->fn_realloc(p, n);
217}
218
219
220/* call custom free() */
221SIXELAPI void
222sixel_allocator_free(
223    sixel_allocator_t   /* in */ *allocator,  /* allocator object */
224    void                /* in */ *p)          /* existing buffer to be freed */
225{
226    /* precondition */
227    assert(allocator);
228    assert(allocator->fn_free);
229
230    allocator->fn_free(p);
231}
232
233
234#if HAVE_TESTS
235volatile int sixel_debug_malloc_counter;
236
237void *
238sixel_bad_malloc(size_t size)
239{
240    return sixel_debug_malloc_counter-- == 0 ? NULL: malloc(size);
241}
242
243
244void *
245sixel_bad_calloc(size_t count, size_t size)
246{
247    (void) count;
248    (void) size;
249
250    return NULL;
251}
252
253
254void *
255sixel_bad_realloc(void *ptr, size_t size)
256{
257    (void) ptr;
258    (void) size;
259
260    return NULL;
261}
262#endif  /* HAVE_TESTS */
263
264#if 0
265int
266rpl_posix_memalign(void **memptr, size_t alignment, size_t size)
267{
268#if HAVE_POSIX_MEMALIGN
269    return posix_memalign(memptr, alignment, size);
270#elif HAVE_ALIGNED_ALLOC
271    *memptr = aligned_alloc(alignment, size);
272    return *memptr ? 0: ENOMEM;
273#elif HAVE_MEMALIGN
274    *memptr = memalign(alignment, size);
275    return *memptr ? 0: ENOMEM;
276#elif HAVE__ALIGNED_MALLOC
277    return _aligned_malloc(size, alignment);
278#else
279# error
280#endif /* _MSC_VER */
281}
282#endif
283
284
285#if HAVE_TESTS
286static int
287test1(void)
288{
289    int nret = EXIT_FAILURE;
290    SIXELSTATUS status;
291    sixel_allocator_t *allocator = NULL;
292
293    status = sixel_allocator_new(NULL, malloc, calloc, realloc, free);
294    if (status != SIXEL_BAD_ARGUMENT) {
295        goto error;
296    }
297
298    status = sixel_allocator_new(&allocator, NULL, calloc, realloc, free);
299    if (SIXEL_FAILED(status)) {
300        goto error;
301    }
302
303    status = sixel_allocator_new(&allocator, malloc, NULL, realloc, free);
304    if (SIXEL_FAILED(status)) {
305        goto error;
306    }
307
308    status = sixel_allocator_new(&allocator, malloc, calloc, NULL, free);
309    if (SIXEL_FAILED(status)) {
310        goto error;
311    }
312
313    status = sixel_allocator_new(&allocator, malloc, calloc, realloc, NULL);
314    if (SIXEL_FAILED(status)) {
315        goto error;
316    }
317
318    nret = EXIT_SUCCESS;
319
320error:
321    return nret;
322}
323
324
325static int
326test2(void)
327{
328    int nret = EXIT_FAILURE;
329    SIXELSTATUS status;
330    sixel_allocator_t *allocator = NULL;
331
332    sixel_debug_malloc_counter = 1;
333
334    status = sixel_allocator_new(&allocator, sixel_bad_malloc, calloc, realloc, free);
335    if (status == SIXEL_BAD_ALLOCATION) {
336        goto error;
337    }
338
339    nret = EXIT_SUCCESS;
340
341error:
342    return nret;
343}
344
345
346SIXELAPI int
347sixel_allocator_tests_main(void)
348{
349    int nret = EXIT_FAILURE;
350    size_t i;
351    typedef int (* testcase)(void);
352
353    static testcase const testcases[] = {
354        test1,
355        test2
356    };
357
358    for (i = 0; i < sizeof(testcases) / sizeof(testcase); ++i) {
359        nret = testcases[i]();
360        if (nret != EXIT_SUCCESS) {
361            goto error;
362        }
363    }
364
365    nret = EXIT_SUCCESS;
366
367error:
368    return nret;
369}
370#endif  /* HAVE_TESTS */
371
372/* emacs Local Variables:      */
373/* emacs mode: c               */
374/* emacs tab-width: 4          */
375/* emacs indent-tabs-mode: nil */
376/* emacs c-basic-offset: 4     */
377/* emacs End:                  */
378/* vim: set expandtab ts=4 sts=4 sw=4 : */
379/* EOF */