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)
18 extern "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 
26 typedef 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 
39 BROTLI_INTERNAL void BrotliInitMemoryManager(
40     MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
41     void* opaque);
42 
43 BROTLI_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 
47 BROTLI_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 /*
60 BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
61 The only purpose of it is to explain static analyzers the state of things.
62 NB: 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 
71 BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
72 
73 /*
74 Dynamically grows array capacity to at least the requested size
75 M: MemoryManager
76 T: data type
77 A: array
78 C: capacity
79 R: 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 /*
96 Appends value and dynamically grows array capacity when needed
97 M: MemoryManager
98 T: data type
99 A: array
100 C: array capacity
101 S: array size
102 V: 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