1 /* Copyright 2015 Google Inc. All Rights Reserved.
3 Distributed under MIT license.
4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
7 /* Algorithms for distributing the literals and commands of a metablock between
8 block types and contexts. */
12 #include <stdlib.h> /* exit, free, malloc */
13 #include <string.h> /* memcpy */
15 #include "../common/platform.h"
16 #include <brotli/types.h>
18 #if defined(__cplusplus) || defined(c_plusplus)
22 #define MAX_PERM_ALLOCATED 128
23 #define MAX_NEW_ALLOCATED 64
24 #define MAX_NEW_FREED 64
26 #define PERM_ALLOCATED_OFFSET 0
27 #define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
28 #define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED)
30 void BrotliInitMemoryManager(
31 MemoryManager
* m
, brotli_alloc_func alloc_func
, brotli_free_func free_func
,
34 m
->alloc_func
= BrotliDefaultAllocFunc
;
35 m
->free_func
= BrotliDefaultFreeFunc
;
38 m
->alloc_func
= alloc_func
;
39 m
->free_func
= free_func
;
42 #if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
43 m
->is_oom
= BROTLI_FALSE
;
44 m
->perm_allocated
= 0;
47 #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
50 #if defined(BROTLI_ENCODER_EXIT_ON_OOM)
52 void* BrotliAllocate(MemoryManager
* m
, size_t n
) {
53 void* result
= m
->alloc_func(m
->opaque
, n
);
54 if (!result
) exit(EXIT_FAILURE
);
58 void BrotliFree(MemoryManager
* m
, void* p
) {
59 m
->free_func(m
->opaque
, p
);
62 void BrotliWipeOutMemoryManager(MemoryManager
* m
) {
66 #else /* BROTLI_ENCODER_EXIT_ON_OOM */
68 static void SortPointers(void** items
, const size_t n
) {
70 static const size_t gaps
[] = {23, 10, 4, 1};
75 for (i
= gap
; i
< n
; ++i
) {
78 for (; j
>= gap
&& tmp
< items
[j
- gap
]; j
-= gap
) {
79 items
[j
] = items
[j
- gap
];
86 static size_t Annihilate(void** a
, size_t a_len
, void** b
, size_t b_len
) {
87 size_t a_read_index
= 0;
88 size_t b_read_index
= 0;
89 size_t a_write_index
= 0;
90 size_t b_write_index
= 0;
91 size_t annihilated
= 0;
92 while (a_read_index
< a_len
&& b_read_index
< b_len
) {
93 if (a
[a_read_index
] == b
[b_read_index
]) {
97 } else if (a
[a_read_index
] < b
[b_read_index
]) {
98 a
[a_write_index
++] = a
[a_read_index
++];
100 b
[b_write_index
++] = b
[b_read_index
++];
103 while (a_read_index
< a_len
) a
[a_write_index
++] = a
[a_read_index
++];
104 while (b_read_index
< b_len
) b
[b_write_index
++] = b
[b_read_index
++];
108 static void CollectGarbagePointers(MemoryManager
* m
) {
110 SortPointers(m
->pointers
+ NEW_ALLOCATED_OFFSET
, m
->new_allocated
);
111 SortPointers(m
->pointers
+ NEW_FREED_OFFSET
, m
->new_freed
);
112 annihilated
= Annihilate(
113 m
->pointers
+ NEW_ALLOCATED_OFFSET
, m
->new_allocated
,
114 m
->pointers
+ NEW_FREED_OFFSET
, m
->new_freed
);
115 m
->new_allocated
-= annihilated
;
116 m
->new_freed
-= annihilated
;
118 if (m
->new_freed
!= 0) {
119 annihilated
= Annihilate(
120 m
->pointers
+ PERM_ALLOCATED_OFFSET
, m
->perm_allocated
,
121 m
->pointers
+ NEW_FREED_OFFSET
, m
->new_freed
);
122 m
->perm_allocated
-= annihilated
;
123 m
->new_freed
-= annihilated
;
124 BROTLI_DCHECK(m
->new_freed
== 0);
127 if (m
->new_allocated
!= 0) {
128 BROTLI_DCHECK(m
->perm_allocated
+ m
->new_allocated
<= MAX_PERM_ALLOCATED
);
129 memcpy(m
->pointers
+ PERM_ALLOCATED_OFFSET
+ m
->perm_allocated
,
130 m
->pointers
+ NEW_ALLOCATED_OFFSET
,
131 sizeof(void*) * m
->new_allocated
);
132 m
->perm_allocated
+= m
->new_allocated
;
133 m
->new_allocated
= 0;
134 SortPointers(m
->pointers
+ PERM_ALLOCATED_OFFSET
, m
->perm_allocated
);
138 void* BrotliAllocate(MemoryManager
* m
, size_t n
) {
139 void* result
= m
->alloc_func(m
->opaque
, n
);
141 m
->is_oom
= BROTLI_TRUE
;
144 if (m
->new_allocated
== MAX_NEW_ALLOCATED
) CollectGarbagePointers(m
);
145 m
->pointers
[NEW_ALLOCATED_OFFSET
+ (m
->new_allocated
++)] = result
;
149 void BrotliFree(MemoryManager
* m
, void* p
) {
151 m
->free_func(m
->opaque
, p
);
152 if (m
->new_freed
== MAX_NEW_FREED
) CollectGarbagePointers(m
);
153 m
->pointers
[NEW_FREED_OFFSET
+ (m
->new_freed
++)] = p
;
156 void BrotliWipeOutMemoryManager(MemoryManager
* m
) {
158 CollectGarbagePointers(m
);
159 /* Now all unfreed pointers are in perm-allocated list. */
160 for (i
= 0; i
< m
->perm_allocated
; ++i
) {
161 m
->free_func(m
->opaque
, m
->pointers
[PERM_ALLOCATED_OFFSET
+ i
]);
163 m
->perm_allocated
= 0;
166 #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
168 #if defined(__cplusplus) || defined(c_plusplus)