Move serialized dictionary feature behind the flag.

BROTLI_SHARED_DICTIONARY_SERIALIZED enum value is a part of API,
but it should not be used (will cause failures).
Changing how serialized dictionaries work won't be considered as an API change, until this feature is enabled.
Enabling this feature in the future will be considered as a "compatible" change.

PiperOrigin-RevId: 558091676
This commit is contained in:
Evgenii Kliuchnikov 2023-08-18 02:55:01 -07:00 committed by Copybara-Service
parent 0f2157cc5e
commit 3ebb2d30ab
8 changed files with 51 additions and 9 deletions

View File

@ -20,6 +20,8 @@
extern "C" {
#endif
#if defined(BROTLI_EXPERIMENTAL)
#define BROTLI_NUM_ENCODED_LENGTHS (SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH \
- SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH + 1)
@ -442,6 +444,8 @@ static BROTLI_BOOL DecodeSharedDictionary(
return ParseDictionary(encoded, size, dict);
}
#endif /* BROTLI_EXPERIMENTAL */
void BrotliSharedDictionaryDestroyInstance(
BrotliSharedDictionary* dict) {
if (!dict) {
@ -464,9 +468,12 @@ BROTLI_BOOL BrotliSharedDictionaryAttach(
if (!dict) {
return BROTLI_FALSE;
}
#if defined(BROTLI_EXPERIMENTAL)
if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) {
return DecodeSharedDictionary(data, data_size, dict);
} else if (type == BROTLI_SHARED_DICTIONARY_RAW) {
}
#endif /* BROTLI_EXPERIMENTAL */
if (type == BROTLI_SHARED_DICTIONARY_RAW) {
if (dict->num_prefix >= SHARED_BROTLI_MAX_COMPOUND_DICTS) {
return BROTLI_FALSE;
}
@ -474,9 +481,8 @@ BROTLI_BOOL BrotliSharedDictionaryAttach(
dict->prefix[dict->num_prefix] = data;
dict->num_prefix++;
return BROTLI_TRUE;
} else {
return BROTLI_FALSE;
}
return BROTLI_FALSE;
}
BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance(

View File

@ -7,6 +7,8 @@
/* Implementation of Brotli compressor. */
#include <brotli/encode.h>
#include <brotli/shared_dictionary.h>
#include <brotli/types.h>
#include <stdlib.h> /* free, malloc */
#include <string.h> /* memcpy, memset */
@ -1707,8 +1709,12 @@ BrotliEncoderPreparedDictionary* BrotliEncoderPrepareDictionary(
const uint8_t data[BROTLI_ARRAY_PARAM(size)], int quality,
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
ManagedDictionary* managed_dictionary = NULL;
if (type != BROTLI_SHARED_DICTIONARY_RAW &&
type != BROTLI_SHARED_DICTIONARY_SERIALIZED) {
BROTLI_BOOL type_is_known = BROTLI_FALSE;
type_is_known |= (type == BROTLI_SHARED_DICTIONARY_RAW);
#if defined(BROTLI_EXPERIMENTAL)
type_is_known |= (type == BROTLI_SHARED_DICTIONARY_SERIALIZED);
#endif /* BROTLI_EXPERIMENTAL */
if (!type_is_known) {
return NULL;
}
managed_dictionary =
@ -1719,7 +1725,9 @@ BrotliEncoderPreparedDictionary* BrotliEncoderPrepareDictionary(
if (type == BROTLI_SHARED_DICTIONARY_RAW) {
managed_dictionary->dictionary = (uint32_t*)CreatePreparedDictionary(
&managed_dictionary->memory_manager_, data, size);
} else {
}
#if defined(BROTLI_EXPERIMENTAL)
if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) {
SharedEncoderDictionary* dict = (SharedEncoderDictionary*)BrotliAllocate(
&managed_dictionary->memory_manager_, sizeof(SharedEncoderDictionary));
managed_dictionary->dictionary = (uint32_t*)dict;
@ -1732,6 +1740,9 @@ BrotliEncoderPreparedDictionary* BrotliEncoderPrepareDictionary(
}
}
}
#else /* BROTLI_EXPERIMENTAL */
(void)quality;
#endif /* BROTLI_EXPERIMENTAL */
if (managed_dictionary->dictionary == NULL) {
BrotliDestroyManagedDictionary(managed_dictionary);
return NULL;

View File

@ -77,6 +77,7 @@ static void BrotliDestroyEncoderDictionary(MemoryManager* m,
BrotliTrieFree(m, &dict->trie);
}
#if defined(BROTLI_EXPERIMENTAL)
/* Word length must be at least 4 bytes */
static uint32_t Hash(const uint8_t* data, int bits) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
@ -481,6 +482,7 @@ static BROTLI_BOOL ComputeDictionary(MemoryManager* m, int quality,
return BROTLI_TRUE;
}
#endif /* BROTLI_EXPERIMENTAL */
void BrotliInitSharedEncoderDictionary(SharedEncoderDictionary* dict) {
dict->magic = kSharedDictionaryMagic;
@ -501,6 +503,7 @@ void BrotliInitSharedEncoderDictionary(SharedEncoderDictionary* dict) {
dict->max_quality = BROTLI_MAX_QUALITY;
}
#if defined(BROTLI_EXPERIMENTAL)
/* TODO(eustas): make sure that tooling will warn user if not all the cutoff
transforms are available (for low-quality encoder). */
static BROTLI_BOOL InitCustomSharedEncoderDictionary(
@ -586,6 +589,7 @@ BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary(
BrotliSharedDictionaryDestroyInstance(decoded_dict);
return success;
}
#endif /* BROTLI_EXPERIMENTAL */
void BrotliCleanupSharedEncoderDictionary(MemoryManager* m,
SharedEncoderDictionary* dict) {

View File

@ -52,8 +52,11 @@ typedef struct BrotliTrie {
BrotliTrieNode root;
} BrotliTrie;
#if defined(BROTLI_EXPERIMENTAL)
BROTLI_INTERNAL const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie,
const BrotliTrieNode* node, uint8_t c);
#endif /* BROTLI_EXPERIMENTAL */
/* Dictionary data (words and transforms) for 1 possible context */
typedef struct BrotliEncoderDictionary {
const BrotliDictionary* words;
@ -129,12 +132,14 @@ typedef struct ManagedDictionary {
BROTLI_INTERNAL void BrotliInitSharedEncoderDictionary(
SharedEncoderDictionary* dict);
#if defined(BROTLI_EXPERIMENTAL)
/* Initializes to shared dictionary that will be parsed from
encoded_dict. Requires that you keep the encoded_dict buffer
around, parts of data will point to it. */
BROTLI_INTERNAL BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary(
MemoryManager* m, const uint8_t* encoded_dict, size_t size,
int quality, SharedEncoderDictionary* dict);
#endif /* BROTLI_EXPERIMENTAL */
BROTLI_INTERNAL void BrotliCleanupSharedEncoderDictionary(
MemoryManager* m, SharedEncoderDictionary* dict);

View File

@ -20,9 +20,11 @@
extern "C" {
#endif
#define MAX_PERM_ALLOCATED 128
/* TODO(eustas): fine-tune for "many slots" case */
#define MAX_NEW_ALLOCATED 64
#define MAX_NEW_FREED 64
#define MAX_PERM_ALLOCATED \
(BROTLI_ENCODER_MEMORY_MANAGER_SLOTS - MAX_NEW_ALLOCATED - MAX_NEW_FREED)
#define PERM_ALLOCATED_OFFSET 0
#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
@ -68,6 +70,7 @@ void BrotliWipeOutMemoryManager(MemoryManager* m) {
static void SortPointers(void** items, const size_t n) {
/* Shell sort. */
/* TODO(eustas): fine-tune for "many slots" case */
static const size_t gaps[] = {23, 10, 4, 1};
int g = 0;
for (; g < 4; ++g) {

View File

@ -24,6 +24,14 @@ extern "C" {
#define BROTLI_ENCODER_EXIT_ON_OOM
#endif
#if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
#if defined(BROTLI_EXPERIMENTAL)
#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 6144
#else /* BROTLI_EXPERIMENTAL */
#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 256
#endif /* BROTLI_EXPERIMENTAL */
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
typedef struct MemoryManager {
brotli_alloc_func alloc_func;
brotli_free_func free_func;
@ -33,7 +41,7 @@ typedef struct MemoryManager {
size_t perm_allocated;
size_t new_allocated;
size_t new_freed;
void* pointers[256];
void* pointers[BROTLI_ENCODER_MEMORY_MANAGER_SLOTS];
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
} MemoryManager;

View File

@ -79,6 +79,7 @@ static BROTLI_BOOL BrotliFindAllStaticDictionaryMatchesFor(
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
size_t min_length, size_t max_length, uint32_t* matches) {
BROTLI_BOOL has_found_match = BROTLI_FALSE;
#if defined(BROTLI_EXPERIMENTAL)
if (dictionary->has_words_heavy) {
const BrotliTrieNode* node = &dictionary->trie.root;
size_t l = 0;
@ -93,6 +94,7 @@ static BROTLI_BOOL BrotliFindAllStaticDictionaryMatchesFor(
}
return has_found_match;
}
#endif /* BROTLI_EXPERIMENTAL */
{
size_t offset = dictionary->buckets[Hash(data)];
BROTLI_BOOL end = !offset;

View File

@ -35,7 +35,10 @@ typedef struct BrotliSharedDictionaryStruct BrotliSharedDictionary;
typedef enum BrotliSharedDictionaryType {
/** Raw LZ77 prefix dictionary. */
BROTLI_SHARED_DICTIONARY_RAW = 0,
/** Serialized shared dictionary. */
/** Serialized shared dictionary.
*
* DO NOT USE: methods accepting this value will fail.
*/
BROTLI_SHARED_DICTIONARY_SERIALIZED = 1
} BrotliSharedDictionaryType;