- Copy Brotli algorithm 3rd party source code for tool Cc: Liming Gao <liming.gao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Bell Song <binx.song@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			198 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			198 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright 2013 Google Inc. All Rights Reserved.
 | |
| 
 | |
|    Distributed under MIT license.
 | |
|    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
 | |
| */
 | |
| 
 | |
| /* Block split point selection utilities. */
 | |
| 
 | |
| #include "./block_splitter.h"
 | |
| 
 | |
| #include <assert.h>
 | |
| #include <string.h>  /* memcpy, memset */
 | |
| 
 | |
| #include "./bit_cost.h"
 | |
| #include "./cluster.h"
 | |
| #include "./command.h"
 | |
| #include "./fast_log.h"
 | |
| #include "./histogram.h"
 | |
| #include "./memory.h"
 | |
| #include "./port.h"
 | |
| #include "./quality.h"
 | |
| 
 | |
| #if defined(__cplusplus) || defined(c_plusplus)
 | |
| extern "C" {
 | |
| #endif
 | |
| 
 | |
| static const size_t kMaxLiteralHistograms = 100;
 | |
| static const size_t kMaxCommandHistograms = 50;
 | |
| static const double kLiteralBlockSwitchCost = 28.1;
 | |
| static const double kCommandBlockSwitchCost = 13.5;
 | |
| static const double kDistanceBlockSwitchCost = 14.6;
 | |
| static const size_t kLiteralStrideLength = 70;
 | |
| static const size_t kCommandStrideLength = 40;
 | |
| static const size_t kSymbolsPerLiteralHistogram = 544;
 | |
| static const size_t kSymbolsPerCommandHistogram = 530;
 | |
| static const size_t kSymbolsPerDistanceHistogram = 544;
 | |
| static const size_t kMinLengthForBlockSplitting = 128;
 | |
| static const size_t kIterMulForRefining = 2;
 | |
| static const size_t kMinItersForRefining = 100;
 | |
| 
 | |
| static size_t CountLiterals(const Command* cmds, const size_t num_commands) {
 | |
|   /* Count how many we have. */
 | |
|   size_t total_length = 0;
 | |
|   size_t i;
 | |
|   for (i = 0; i < num_commands; ++i) {
 | |
|     total_length += cmds[i].insert_len_;
 | |
|   }
 | |
|   return total_length;
 | |
| }
 | |
| 
 | |
| static void CopyLiteralsToByteArray(const Command* cmds,
 | |
|                                     const size_t num_commands,
 | |
|                                     const uint8_t* data,
 | |
|                                     const size_t offset,
 | |
|                                     const size_t mask,
 | |
|                                     uint8_t* literals) {
 | |
|   size_t pos = 0;
 | |
|   size_t from_pos = offset & mask;
 | |
|   size_t i;
 | |
|   for (i = 0; i < num_commands; ++i) {
 | |
|     size_t insert_len = cmds[i].insert_len_;
 | |
|     if (from_pos + insert_len > mask) {
 | |
|       size_t head_size = mask + 1 - from_pos;
 | |
|       memcpy(literals + pos, data + from_pos, head_size);
 | |
|       from_pos = 0;
 | |
|       pos += head_size;
 | |
|       insert_len -= head_size;
 | |
|     }
 | |
|     if (insert_len > 0) {
 | |
|       memcpy(literals + pos, data + from_pos, insert_len);
 | |
|       pos += insert_len;
 | |
|     }
 | |
|     from_pos = (from_pos + insert_len + CommandCopyLen(&cmds[i])) & mask;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static BROTLI_INLINE unsigned int MyRand(unsigned int* seed) {
 | |
|   *seed *= 16807U;
 | |
|   if (*seed == 0) {
 | |
|     *seed = 1;
 | |
|   }
 | |
|   return *seed;
 | |
| }
 | |
| 
 | |
| static BROTLI_INLINE double BitCost(size_t count) {
 | |
|   return count == 0 ? -2.0 : FastLog2(count);
 | |
| }
 | |
| 
 | |
| #define HISTOGRAMS_PER_BATCH 64
 | |
| #define CLUSTERS_PER_BATCH 16
 | |
| 
 | |
| #define FN(X) X ## Literal
 | |
| #define DataType uint8_t
 | |
| /* NOLINTNEXTLINE(build/include) */
 | |
| #include "./block_splitter_inc.h"
 | |
| #undef DataType
 | |
| #undef FN
 | |
| 
 | |
| #define FN(X) X ## Command
 | |
| #define DataType uint16_t
 | |
| /* NOLINTNEXTLINE(build/include) */
 | |
| #include "./block_splitter_inc.h"
 | |
| #undef FN
 | |
| 
 | |
| #define FN(X) X ## Distance
 | |
| /* NOLINTNEXTLINE(build/include) */
 | |
| #include "./block_splitter_inc.h"
 | |
| #undef DataType
 | |
| #undef FN
 | |
| 
 | |
| void BrotliInitBlockSplit(BlockSplit* self) {
 | |
|   self->num_types = 0;
 | |
|   self->num_blocks = 0;
 | |
|   self->types = 0;
 | |
|   self->lengths = 0;
 | |
|   self->types_alloc_size = 0;
 | |
|   self->lengths_alloc_size = 0;
 | |
| }
 | |
| 
 | |
| void BrotliDestroyBlockSplit(MemoryManager* m, BlockSplit* self) {
 | |
|   BROTLI_FREE(m, self->types);
 | |
|   BROTLI_FREE(m, self->lengths);
 | |
| }
 | |
| 
 | |
| void BrotliSplitBlock(MemoryManager* m,
 | |
|                       const Command* cmds,
 | |
|                       const size_t num_commands,
 | |
|                       const uint8_t* data,
 | |
|                       const size_t pos,
 | |
|                       const size_t mask,
 | |
|                       const BrotliEncoderParams* params,
 | |
|                       BlockSplit* literal_split,
 | |
|                       BlockSplit* insert_and_copy_split,
 | |
|                       BlockSplit* dist_split) {
 | |
|   {
 | |
|     size_t literals_count = CountLiterals(cmds, num_commands);
 | |
|     uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count);
 | |
|     if (BROTLI_IS_OOM(m)) return;
 | |
|     /* Create a continuous array of literals. */
 | |
|     CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
 | |
|     /* Create the block split on the array of literals.
 | |
|        Literal histograms have alphabet size 256. */
 | |
|     SplitByteVectorLiteral(
 | |
|         m, literals, literals_count,
 | |
|         kSymbolsPerLiteralHistogram, kMaxLiteralHistograms,
 | |
|         kLiteralStrideLength, kLiteralBlockSwitchCost, params,
 | |
|         literal_split);
 | |
|     if (BROTLI_IS_OOM(m)) return;
 | |
|     BROTLI_FREE(m, literals);
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     /* Compute prefix codes for commands. */
 | |
|     uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands);
 | |
|     size_t i;
 | |
|     if (BROTLI_IS_OOM(m)) return;
 | |
|     for (i = 0; i < num_commands; ++i) {
 | |
|       insert_and_copy_codes[i] = cmds[i].cmd_prefix_;
 | |
|     }
 | |
|     /* Create the block split on the array of command prefixes. */
 | |
|     SplitByteVectorCommand(
 | |
|         m, insert_and_copy_codes, num_commands,
 | |
|         kSymbolsPerCommandHistogram, kMaxCommandHistograms,
 | |
|         kCommandStrideLength, kCommandBlockSwitchCost, params,
 | |
|         insert_and_copy_split);
 | |
|     if (BROTLI_IS_OOM(m)) return;
 | |
|     /* TODO: reuse for distances? */
 | |
|     BROTLI_FREE(m, insert_and_copy_codes);
 | |
|   }
 | |
| 
 | |
|   {
 | |
|     /* Create a continuous array of distance prefixes. */
 | |
|     uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands);
 | |
|     size_t j = 0;
 | |
|     size_t i;
 | |
|     if (BROTLI_IS_OOM(m)) return;
 | |
|     for (i = 0; i < num_commands; ++i) {
 | |
|       const Command* cmd = &cmds[i];
 | |
|       if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
 | |
|         distance_prefixes[j++] = cmd->dist_prefix_;
 | |
|       }
 | |
|     }
 | |
|     /* Create the block split on the array of distance prefixes. */
 | |
|     SplitByteVectorDistance(
 | |
|         m, distance_prefixes, j,
 | |
|         kSymbolsPerDistanceHistogram, kMaxCommandHistograms,
 | |
|         kCommandStrideLength, kDistanceBlockSwitchCost, params,
 | |
|         dist_split);
 | |
|     if (BROTLI_IS_OOM(m)) return;
 | |
|     BROTLI_FREE(m, distance_prefixes);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| #if defined(__cplusplus) || defined(c_plusplus)
 | |
| }  /* extern "C" */
 | |
| #endif
 |