126fa459cSmrg/* Copyright 2015 Google Inc. All Rights Reserved. 226fa459cSmrg 326fa459cSmrg Distributed under MIT license. 426fa459cSmrg See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 526fa459cSmrg*/ 626fa459cSmrg 726fa459cSmrg/* Algorithms for distributing the literals and commands of a metablock between 826fa459cSmrg block types and contexts. */ 926fa459cSmrg 1026fa459cSmrg#include "./memory.h" 1126fa459cSmrg 1226fa459cSmrg#include <stdlib.h> /* exit, free, malloc */ 1326fa459cSmrg#include <string.h> /* memcpy */ 1426fa459cSmrg 1526fa459cSmrg#include "../common/platform.h" 1626fa459cSmrg#include <brotli/types.h> 1726fa459cSmrg 1826fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus) 1926fa459cSmrgextern "C" { 2026fa459cSmrg#endif 2126fa459cSmrg 2226fa459cSmrg#define MAX_PERM_ALLOCATED 128 2326fa459cSmrg#define MAX_NEW_ALLOCATED 64 2426fa459cSmrg#define MAX_NEW_FREED 64 2526fa459cSmrg 2626fa459cSmrg#define PERM_ALLOCATED_OFFSET 0 2726fa459cSmrg#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED 2826fa459cSmrg#define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED) 2926fa459cSmrg 3026fa459cSmrgvoid BrotliInitMemoryManager( 3126fa459cSmrg MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func, 3226fa459cSmrg void* opaque) { 3326fa459cSmrg if (!alloc_func) { 3426fa459cSmrg m->alloc_func = BrotliDefaultAllocFunc; 3526fa459cSmrg m->free_func = BrotliDefaultFreeFunc; 3626fa459cSmrg m->opaque = 0; 3726fa459cSmrg } else { 3826fa459cSmrg m->alloc_func = alloc_func; 3926fa459cSmrg m->free_func = free_func; 4026fa459cSmrg m->opaque = opaque; 4126fa459cSmrg } 4226fa459cSmrg#if !defined(BROTLI_ENCODER_EXIT_ON_OOM) 4326fa459cSmrg m->is_oom = BROTLI_FALSE; 4426fa459cSmrg m->perm_allocated = 0; 4526fa459cSmrg m->new_allocated = 0; 4626fa459cSmrg m->new_freed = 0; 4726fa459cSmrg#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ 4826fa459cSmrg} 4926fa459cSmrg 5026fa459cSmrg#if defined(BROTLI_ENCODER_EXIT_ON_OOM) 5126fa459cSmrg 5226fa459cSmrgvoid* BrotliAllocate(MemoryManager* m, size_t n) { 5326fa459cSmrg void* result = m->alloc_func(m->opaque, n); 5426fa459cSmrg if (!result) exit(EXIT_FAILURE); 5526fa459cSmrg return result; 5626fa459cSmrg} 5726fa459cSmrg 5826fa459cSmrgvoid BrotliFree(MemoryManager* m, void* p) { 5926fa459cSmrg m->free_func(m->opaque, p); 6026fa459cSmrg} 6126fa459cSmrg 6226fa459cSmrgvoid BrotliWipeOutMemoryManager(MemoryManager* m) { 6326fa459cSmrg BROTLI_UNUSED(m); 6426fa459cSmrg} 6526fa459cSmrg 6626fa459cSmrg#else /* BROTLI_ENCODER_EXIT_ON_OOM */ 6726fa459cSmrg 6826fa459cSmrgstatic void SortPointers(void** items, const size_t n) { 6926fa459cSmrg /* Shell sort. */ 7026fa459cSmrg static const size_t gaps[] = {23, 10, 4, 1}; 7126fa459cSmrg int g = 0; 7226fa459cSmrg for (; g < 4; ++g) { 7326fa459cSmrg size_t gap = gaps[g]; 7426fa459cSmrg size_t i; 7526fa459cSmrg for (i = gap; i < n; ++i) { 7626fa459cSmrg size_t j = i; 7726fa459cSmrg void* tmp = items[i]; 7826fa459cSmrg for (; j >= gap && tmp < items[j - gap]; j -= gap) { 7926fa459cSmrg items[j] = items[j - gap]; 8026fa459cSmrg } 8126fa459cSmrg items[j] = tmp; 8226fa459cSmrg } 8326fa459cSmrg } 8426fa459cSmrg} 8526fa459cSmrg 8626fa459cSmrgstatic size_t Annihilate(void** a, size_t a_len, void** b, size_t b_len) { 8726fa459cSmrg size_t a_read_index = 0; 8826fa459cSmrg size_t b_read_index = 0; 8926fa459cSmrg size_t a_write_index = 0; 9026fa459cSmrg size_t b_write_index = 0; 9126fa459cSmrg size_t annihilated = 0; 9226fa459cSmrg while (a_read_index < a_len && b_read_index < b_len) { 9326fa459cSmrg if (a[a_read_index] == b[b_read_index]) { 9426fa459cSmrg a_read_index++; 9526fa459cSmrg b_read_index++; 9626fa459cSmrg annihilated++; 9726fa459cSmrg } else if (a[a_read_index] < b[b_read_index]) { 9826fa459cSmrg a[a_write_index++] = a[a_read_index++]; 9926fa459cSmrg } else { 10026fa459cSmrg b[b_write_index++] = b[b_read_index++]; 10126fa459cSmrg } 10226fa459cSmrg } 10326fa459cSmrg while (a_read_index < a_len) a[a_write_index++] = a[a_read_index++]; 10426fa459cSmrg while (b_read_index < b_len) b[b_write_index++] = b[b_read_index++]; 10526fa459cSmrg return annihilated; 10626fa459cSmrg} 10726fa459cSmrg 10826fa459cSmrgstatic void CollectGarbagePointers(MemoryManager* m) { 10926fa459cSmrg size_t annihilated; 11026fa459cSmrg SortPointers(m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated); 11126fa459cSmrg SortPointers(m->pointers + NEW_FREED_OFFSET, m->new_freed); 11226fa459cSmrg annihilated = Annihilate( 11326fa459cSmrg m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated, 11426fa459cSmrg m->pointers + NEW_FREED_OFFSET, m->new_freed); 11526fa459cSmrg m->new_allocated -= annihilated; 11626fa459cSmrg m->new_freed -= annihilated; 11726fa459cSmrg 11826fa459cSmrg if (m->new_freed != 0) { 11926fa459cSmrg annihilated = Annihilate( 12026fa459cSmrg m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated, 12126fa459cSmrg m->pointers + NEW_FREED_OFFSET, m->new_freed); 12226fa459cSmrg m->perm_allocated -= annihilated; 12326fa459cSmrg m->new_freed -= annihilated; 12426fa459cSmrg BROTLI_DCHECK(m->new_freed == 0); 12526fa459cSmrg } 12626fa459cSmrg 12726fa459cSmrg if (m->new_allocated != 0) { 12826fa459cSmrg BROTLI_DCHECK(m->perm_allocated + m->new_allocated <= MAX_PERM_ALLOCATED); 12926fa459cSmrg memcpy(m->pointers + PERM_ALLOCATED_OFFSET + m->perm_allocated, 13026fa459cSmrg m->pointers + NEW_ALLOCATED_OFFSET, 13126fa459cSmrg sizeof(void*) * m->new_allocated); 13226fa459cSmrg m->perm_allocated += m->new_allocated; 13326fa459cSmrg m->new_allocated = 0; 13426fa459cSmrg SortPointers(m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated); 13526fa459cSmrg } 13626fa459cSmrg} 13726fa459cSmrg 13826fa459cSmrgvoid* BrotliAllocate(MemoryManager* m, size_t n) { 13926fa459cSmrg void* result = m->alloc_func(m->opaque, n); 14026fa459cSmrg if (!result) { 14126fa459cSmrg m->is_oom = BROTLI_TRUE; 14226fa459cSmrg return NULL; 14326fa459cSmrg } 14426fa459cSmrg if (m->new_allocated == MAX_NEW_ALLOCATED) CollectGarbagePointers(m); 14526fa459cSmrg m->pointers[NEW_ALLOCATED_OFFSET + (m->new_allocated++)] = result; 14626fa459cSmrg return result; 14726fa459cSmrg} 14826fa459cSmrg 14926fa459cSmrgvoid BrotliFree(MemoryManager* m, void* p) { 15026fa459cSmrg if (!p) return; 15126fa459cSmrg m->free_func(m->opaque, p); 15226fa459cSmrg if (m->new_freed == MAX_NEW_FREED) CollectGarbagePointers(m); 15326fa459cSmrg m->pointers[NEW_FREED_OFFSET + (m->new_freed++)] = p; 15426fa459cSmrg} 15526fa459cSmrg 15626fa459cSmrgvoid BrotliWipeOutMemoryManager(MemoryManager* m) { 15726fa459cSmrg size_t i; 15826fa459cSmrg CollectGarbagePointers(m); 15926fa459cSmrg /* Now all unfreed pointers are in perm-allocated list. */ 16026fa459cSmrg for (i = 0; i < m->perm_allocated; ++i) { 16126fa459cSmrg m->free_func(m->opaque, m->pointers[PERM_ALLOCATED_OFFSET + i]); 16226fa459cSmrg } 16326fa459cSmrg m->perm_allocated = 0; 16426fa459cSmrg} 16526fa459cSmrg 16626fa459cSmrg#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ 16726fa459cSmrg 16826fa459cSmrg#if defined(__cplusplus) || defined(c_plusplus) 16926fa459cSmrg} /* extern "C" */ 17026fa459cSmrg#endif 171