1/* Copyright 2016 Google Inc. All Rights Reserved.
2
3   Distributed under MIT license.
4   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5*/
6
7/* Macros for memory management. */
8
9#ifndef BROTLI_ENC_MEMORY_H_
10#define BROTLI_ENC_MEMORY_H_
11
12#include <string.h>  /* memcpy */
13
14#include "../common/platform.h"
15#include <brotli/types.h>
16
17#if defined(__cplusplus) || defined(c_plusplus)
18extern "C" {
19#endif
20
21#if !defined(BROTLI_ENCODER_CLEANUP_ON_OOM) && \
22    !defined(BROTLI_ENCODER_EXIT_ON_OOM)
23#define BROTLI_ENCODER_EXIT_ON_OOM
24#endif
25
26typedef struct MemoryManager {
27  brotli_alloc_func alloc_func;
28  brotli_free_func free_func;
29  void* opaque;
30#if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
31  BROTLI_BOOL is_oom;
32  size_t perm_allocated;
33  size_t new_allocated;
34  size_t new_freed;
35  void* pointers[256];
36#endif  /* BROTLI_ENCODER_EXIT_ON_OOM */
37} MemoryManager;
38
39BROTLI_INTERNAL void BrotliInitMemoryManager(
40    MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
41    void* opaque);
42
43BROTLI_INTERNAL void* BrotliAllocate(MemoryManager* m, size_t n);
44#define BROTLI_ALLOC(M, T, N)                               \
45  ((N) > 0 ? ((T*)BrotliAllocate((M), (N) * sizeof(T))) : NULL)
46
47BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
48#define BROTLI_FREE(M, P) { \
49  BrotliFree((M), (P));     \
50  P = NULL;                 \
51}
52
53#if defined(BROTLI_ENCODER_EXIT_ON_OOM)
54#define BROTLI_IS_OOM(M) (!!0)
55#else  /* BROTLI_ENCODER_EXIT_ON_OOM */
56#define BROTLI_IS_OOM(M) (!!(M)->is_oom)
57#endif  /* BROTLI_ENCODER_EXIT_ON_OOM */
58
59/*
60BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
61The only purpose of it is to explain static analyzers the state of things.
62NB: use ONLY together with BROTLI_IS_OOM
63    AND ONLY for allocations in the current scope.
64 */
65#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM)
66#define BROTLI_IS_NULL(A) ((A) == nullptr)
67#else  /* defined(__clang_analyzer__) */
68#define BROTLI_IS_NULL(A) (!!0)
69#endif  /* defined(__clang_analyzer__) */
70
71BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
72
73/*
74Dynamically grows array capacity to at least the requested size
75M: MemoryManager
76T: data type
77A: array
78C: capacity
79R: requested size
80*/
81#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) {                    \
82  if (C < (R)) {                                                   \
83    size_t _new_size = (C == 0) ? (R) : C;                         \
84    T* new_array;                                                  \
85    while (_new_size < (R)) _new_size *= 2;                        \
86    new_array = BROTLI_ALLOC((M), T, _new_size);                   \
87    if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \
88      memcpy(new_array, A, C * sizeof(T));                         \
89    BROTLI_FREE((M), A);                                           \
90    A = new_array;                                                 \
91    C = _new_size;                                                 \
92  }                                                                \
93}
94
95/*
96Appends value and dynamically grows array capacity when needed
97M: MemoryManager
98T: data type
99A: array
100C: array capacity
101S: array size
102V: value to append
103*/
104#define BROTLI_ENSURE_CAPACITY_APPEND(M, T, A, C, S, V) { \
105  (S)++;                                                  \
106  BROTLI_ENSURE_CAPACITY(M, T, A, C, S);                  \
107  A[(S) - 1] = (V);                                       \
108}
109
110#if defined(__cplusplus) || defined(c_plusplus)
111}  /* extern "C" */
112#endif
113
114#endif  /* BROTLI_ENC_MEMORY_H_ */
115