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. */
13 #include <stdlib.h> /* exit, free, malloc */
14 #include <string.h> /* memcpy */
16 #include "../common/types.h"
19 #if defined(__cplusplus) || defined(c_plusplus)
23 #define MAX_PERM_ALLOCATED 128
24 #define MAX_NEW_ALLOCATED 64
25 #define MAX_NEW_FREED 64
27 #define PERM_ALLOCATED_OFFSET 0
28 #define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
29 #define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED)
31 static void* DefaultAllocFunc(void* opaque
, size_t size
) {
32 BROTLI_UNUSED(opaque
);
36 static void DefaultFreeFunc(void* opaque
, void* address
) {
37 BROTLI_UNUSED(opaque
);
41 void BrotliInitMemoryManager(
42 MemoryManager
* m
, brotli_alloc_func alloc_func
, brotli_free_func free_func
,
45 m
->alloc_func
= DefaultAllocFunc
;
46 m
->free_func
= DefaultFreeFunc
;
49 m
->alloc_func
= alloc_func
;
50 m
->free_func
= free_func
;
53 #if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
54 m
->is_oom
= BROTLI_FALSE
;
55 m
->perm_allocated
= 0;
58 #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
61 #if defined(BROTLI_ENCODER_EXIT_ON_OOM)
63 void* BrotliAllocate(MemoryManager
* m
, size_t n
) {
64 void* result
= m
->alloc_func(m
->opaque
, n
);
65 if (!result
) exit(EXIT_FAILURE
);
69 void BrotliFree(MemoryManager
* m
, void* p
) {
70 m
->free_func(m
->opaque
, p
);
73 void BrotliWipeOutMemoryManager(MemoryManager
* m
) {
77 #else /* BROTLI_ENCODER_EXIT_ON_OOM */
79 static void SortPointers(void** items
, const size_t n
) {
81 static const size_t gaps
[] = {23, 10, 4, 1};
86 for (i
= gap
; i
< n
; ++i
) {
89 for (; j
>= gap
&& tmp
< items
[j
- gap
]; j
-= gap
) {
90 items
[j
] = items
[j
- gap
];
97 static size_t Annihilate(void** a
, size_t a_len
, void** b
, size_t b_len
) {
98 size_t a_read_index
= 0;
99 size_t b_read_index
= 0;
100 size_t a_write_index
= 0;
101 size_t b_write_index
= 0;
102 size_t annihilated
= 0;
103 while (a_read_index
< a_len
&& b_read_index
< b_len
) {
104 if (a
[a_read_index
] == b
[b_read_index
]) {
108 } else if (a
[a_read_index
] < b
[b_read_index
]) {
109 a
[a_write_index
++] = a
[a_read_index
++];
111 b
[b_write_index
++] = b
[b_read_index
++];
114 while (a_read_index
< a_len
) a
[a_write_index
++] = a
[a_read_index
++];
115 while (b_read_index
< b_len
) b
[b_write_index
++] = b
[b_read_index
++];
119 static void CollectGarbagePointers(MemoryManager
* m
) {
121 SortPointers(m
->pointers
+ NEW_ALLOCATED_OFFSET
, m
->new_allocated
);
122 SortPointers(m
->pointers
+ NEW_FREED_OFFSET
, m
->new_freed
);
123 annihilated
= Annihilate(
124 m
->pointers
+ NEW_ALLOCATED_OFFSET
, m
->new_allocated
,
125 m
->pointers
+ NEW_FREED_OFFSET
, m
->new_freed
);
126 m
->new_allocated
-= annihilated
;
127 m
->new_freed
-= annihilated
;
129 if (m
->new_freed
!= 0) {
130 annihilated
= Annihilate(
131 m
->pointers
+ PERM_ALLOCATED_OFFSET
, m
->perm_allocated
,
132 m
->pointers
+ NEW_FREED_OFFSET
, m
->new_freed
);
133 m
->perm_allocated
-= annihilated
;
134 m
->new_freed
-= annihilated
;
135 assert(m
->new_freed
== 0);
138 if (m
->new_allocated
!= 0) {
139 assert(m
->perm_allocated
+ m
->new_allocated
<= MAX_PERM_ALLOCATED
);
140 memcpy(m
->pointers
+ PERM_ALLOCATED_OFFSET
+ m
->perm_allocated
,
141 m
->pointers
+ NEW_ALLOCATED_OFFSET
,
142 sizeof(void*) * m
->new_allocated
);
143 m
->perm_allocated
+= m
->new_allocated
;
144 m
->new_allocated
= 0;
145 SortPointers(m
->pointers
+ PERM_ALLOCATED_OFFSET
, m
->perm_allocated
);
149 void* BrotliAllocate(MemoryManager
* m
, size_t n
) {
150 void* result
= m
->alloc_func(m
->opaque
, n
);
152 m
->is_oom
= BROTLI_TRUE
;
155 if (m
->new_allocated
== MAX_NEW_ALLOCATED
) CollectGarbagePointers(m
);
156 m
->pointers
[NEW_ALLOCATED_OFFSET
+ (m
->new_allocated
++)] = result
;
160 void BrotliFree(MemoryManager
* m
, void* p
) {
162 m
->free_func(m
->opaque
, p
);
163 if (m
->new_freed
== MAX_NEW_FREED
) CollectGarbagePointers(m
);
164 m
->pointers
[NEW_FREED_OFFSET
+ (m
->new_freed
++)] = p
;
167 void BrotliWipeOutMemoryManager(MemoryManager
* m
) {
169 CollectGarbagePointers(m
);
170 /* Now all unfreed pointers are in perm-allocated list. */
171 for (i
= 0; i
< m
->perm_allocated
; ++i
) {
172 m
->free_func(m
->opaque
, m
->pointers
[PERM_ALLOCATED_OFFSET
+ i
]);
174 m
->perm_allocated
= 0;
177 #endif /* BROTLI_ENCODER_EXIT_ON_OOM */
179 #if defined(__cplusplus) || defined(c_plusplus)