11cb0ef41Sopenharmony_ci/* Copyright 2015 Google Inc. All Rights Reserved. 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci Distributed under MIT license. 41cb0ef41Sopenharmony_ci See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 51cb0ef41Sopenharmony_ci*/ 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci/* Algorithms for distributing the literals and commands of a metablock between 81cb0ef41Sopenharmony_ci block types and contexts. */ 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "./memory.h" 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#include <stdlib.h> /* exit, free, malloc */ 131cb0ef41Sopenharmony_ci#include <string.h> /* memcpy */ 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci#include "../common/platform.h" 161cb0ef41Sopenharmony_ci#include <brotli/types.h> 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus) 191cb0ef41Sopenharmony_ciextern "C" { 201cb0ef41Sopenharmony_ci#endif 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#define MAX_PERM_ALLOCATED 128 231cb0ef41Sopenharmony_ci#define MAX_NEW_ALLOCATED 64 241cb0ef41Sopenharmony_ci#define MAX_NEW_FREED 64 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#define PERM_ALLOCATED_OFFSET 0 271cb0ef41Sopenharmony_ci#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED 281cb0ef41Sopenharmony_ci#define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED) 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_civoid BrotliInitMemoryManager( 311cb0ef41Sopenharmony_ci MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func, 321cb0ef41Sopenharmony_ci void* opaque) { 331cb0ef41Sopenharmony_ci if (!alloc_func) { 341cb0ef41Sopenharmony_ci m->alloc_func = BrotliDefaultAllocFunc; 351cb0ef41Sopenharmony_ci m->free_func = BrotliDefaultFreeFunc; 361cb0ef41Sopenharmony_ci m->opaque = 0; 371cb0ef41Sopenharmony_ci } else { 381cb0ef41Sopenharmony_ci m->alloc_func = alloc_func; 391cb0ef41Sopenharmony_ci m->free_func = free_func; 401cb0ef41Sopenharmony_ci m->opaque = opaque; 411cb0ef41Sopenharmony_ci } 421cb0ef41Sopenharmony_ci#if !defined(BROTLI_ENCODER_EXIT_ON_OOM) 431cb0ef41Sopenharmony_ci m->is_oom = BROTLI_FALSE; 441cb0ef41Sopenharmony_ci m->perm_allocated = 0; 451cb0ef41Sopenharmony_ci m->new_allocated = 0; 461cb0ef41Sopenharmony_ci m->new_freed = 0; 471cb0ef41Sopenharmony_ci#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ 481cb0ef41Sopenharmony_ci} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci#if defined(BROTLI_ENCODER_EXIT_ON_OOM) 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_civoid* BrotliAllocate(MemoryManager* m, size_t n) { 531cb0ef41Sopenharmony_ci void* result = m->alloc_func(m->opaque, n); 541cb0ef41Sopenharmony_ci if (!result) exit(EXIT_FAILURE); 551cb0ef41Sopenharmony_ci return result; 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_civoid BrotliFree(MemoryManager* m, void* p) { 591cb0ef41Sopenharmony_ci m->free_func(m->opaque, p); 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_civoid BrotliWipeOutMemoryManager(MemoryManager* m) { 631cb0ef41Sopenharmony_ci BROTLI_UNUSED(m); 641cb0ef41Sopenharmony_ci} 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci#else /* BROTLI_ENCODER_EXIT_ON_OOM */ 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_cistatic void SortPointers(void** items, const size_t n) { 691cb0ef41Sopenharmony_ci /* Shell sort. */ 701cb0ef41Sopenharmony_ci static const size_t gaps[] = {23, 10, 4, 1}; 711cb0ef41Sopenharmony_ci int g = 0; 721cb0ef41Sopenharmony_ci for (; g < 4; ++g) { 731cb0ef41Sopenharmony_ci size_t gap = gaps[g]; 741cb0ef41Sopenharmony_ci size_t i; 751cb0ef41Sopenharmony_ci for (i = gap; i < n; ++i) { 761cb0ef41Sopenharmony_ci size_t j = i; 771cb0ef41Sopenharmony_ci void* tmp = items[i]; 781cb0ef41Sopenharmony_ci for (; j >= gap && tmp < items[j - gap]; j -= gap) { 791cb0ef41Sopenharmony_ci items[j] = items[j - gap]; 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci items[j] = tmp; 821cb0ef41Sopenharmony_ci } 831cb0ef41Sopenharmony_ci } 841cb0ef41Sopenharmony_ci} 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_cistatic size_t Annihilate(void** a, size_t a_len, void** b, size_t b_len) { 871cb0ef41Sopenharmony_ci size_t a_read_index = 0; 881cb0ef41Sopenharmony_ci size_t b_read_index = 0; 891cb0ef41Sopenharmony_ci size_t a_write_index = 0; 901cb0ef41Sopenharmony_ci size_t b_write_index = 0; 911cb0ef41Sopenharmony_ci size_t annihilated = 0; 921cb0ef41Sopenharmony_ci while (a_read_index < a_len && b_read_index < b_len) { 931cb0ef41Sopenharmony_ci if (a[a_read_index] == b[b_read_index]) { 941cb0ef41Sopenharmony_ci a_read_index++; 951cb0ef41Sopenharmony_ci b_read_index++; 961cb0ef41Sopenharmony_ci annihilated++; 971cb0ef41Sopenharmony_ci } else if (a[a_read_index] < b[b_read_index]) { 981cb0ef41Sopenharmony_ci a[a_write_index++] = a[a_read_index++]; 991cb0ef41Sopenharmony_ci } else { 1001cb0ef41Sopenharmony_ci b[b_write_index++] = b[b_read_index++]; 1011cb0ef41Sopenharmony_ci } 1021cb0ef41Sopenharmony_ci } 1031cb0ef41Sopenharmony_ci while (a_read_index < a_len) a[a_write_index++] = a[a_read_index++]; 1041cb0ef41Sopenharmony_ci while (b_read_index < b_len) b[b_write_index++] = b[b_read_index++]; 1051cb0ef41Sopenharmony_ci return annihilated; 1061cb0ef41Sopenharmony_ci} 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_cistatic void CollectGarbagePointers(MemoryManager* m) { 1091cb0ef41Sopenharmony_ci size_t annihilated; 1101cb0ef41Sopenharmony_ci SortPointers(m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated); 1111cb0ef41Sopenharmony_ci SortPointers(m->pointers + NEW_FREED_OFFSET, m->new_freed); 1121cb0ef41Sopenharmony_ci annihilated = Annihilate( 1131cb0ef41Sopenharmony_ci m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated, 1141cb0ef41Sopenharmony_ci m->pointers + NEW_FREED_OFFSET, m->new_freed); 1151cb0ef41Sopenharmony_ci m->new_allocated -= annihilated; 1161cb0ef41Sopenharmony_ci m->new_freed -= annihilated; 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci if (m->new_freed != 0) { 1191cb0ef41Sopenharmony_ci annihilated = Annihilate( 1201cb0ef41Sopenharmony_ci m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated, 1211cb0ef41Sopenharmony_ci m->pointers + NEW_FREED_OFFSET, m->new_freed); 1221cb0ef41Sopenharmony_ci m->perm_allocated -= annihilated; 1231cb0ef41Sopenharmony_ci m->new_freed -= annihilated; 1241cb0ef41Sopenharmony_ci BROTLI_DCHECK(m->new_freed == 0); 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci if (m->new_allocated != 0) { 1281cb0ef41Sopenharmony_ci BROTLI_DCHECK(m->perm_allocated + m->new_allocated <= MAX_PERM_ALLOCATED); 1291cb0ef41Sopenharmony_ci memcpy(m->pointers + PERM_ALLOCATED_OFFSET + m->perm_allocated, 1301cb0ef41Sopenharmony_ci m->pointers + NEW_ALLOCATED_OFFSET, 1311cb0ef41Sopenharmony_ci sizeof(void*) * m->new_allocated); 1321cb0ef41Sopenharmony_ci m->perm_allocated += m->new_allocated; 1331cb0ef41Sopenharmony_ci m->new_allocated = 0; 1341cb0ef41Sopenharmony_ci SortPointers(m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci} 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_civoid* BrotliAllocate(MemoryManager* m, size_t n) { 1391cb0ef41Sopenharmony_ci void* result = m->alloc_func(m->opaque, n); 1401cb0ef41Sopenharmony_ci if (!result) { 1411cb0ef41Sopenharmony_ci m->is_oom = BROTLI_TRUE; 1421cb0ef41Sopenharmony_ci return NULL; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci if (m->new_allocated == MAX_NEW_ALLOCATED) CollectGarbagePointers(m); 1451cb0ef41Sopenharmony_ci m->pointers[NEW_ALLOCATED_OFFSET + (m->new_allocated++)] = result; 1461cb0ef41Sopenharmony_ci return result; 1471cb0ef41Sopenharmony_ci} 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_civoid BrotliFree(MemoryManager* m, void* p) { 1501cb0ef41Sopenharmony_ci if (!p) return; 1511cb0ef41Sopenharmony_ci m->free_func(m->opaque, p); 1521cb0ef41Sopenharmony_ci if (m->new_freed == MAX_NEW_FREED) CollectGarbagePointers(m); 1531cb0ef41Sopenharmony_ci m->pointers[NEW_FREED_OFFSET + (m->new_freed++)] = p; 1541cb0ef41Sopenharmony_ci} 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_civoid BrotliWipeOutMemoryManager(MemoryManager* m) { 1571cb0ef41Sopenharmony_ci size_t i; 1581cb0ef41Sopenharmony_ci CollectGarbagePointers(m); 1591cb0ef41Sopenharmony_ci /* Now all unfreed pointers are in perm-allocated list. */ 1601cb0ef41Sopenharmony_ci for (i = 0; i < m->perm_allocated; ++i) { 1611cb0ef41Sopenharmony_ci m->free_func(m->opaque, m->pointers[PERM_ALLOCATED_OFFSET + i]); 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci m->perm_allocated = 0; 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci#if defined(__cplusplus) || defined(c_plusplus) 1691cb0ef41Sopenharmony_ci} /* extern "C" */ 1701cb0ef41Sopenharmony_ci#endif 171