block_splitter.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package brotli
  2. /* Copyright 2013 Google Inc. All Rights Reserved.
  3. Distributed under MIT license.
  4. See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
  5. */
  6. /* Block split point selection utilities. */
  7. type blockSplit struct {
  8. num_types uint
  9. num_blocks uint
  10. types []byte
  11. lengths []uint32
  12. types_alloc_size uint
  13. lengths_alloc_size uint
  14. }
  15. const (
  16. kMaxLiteralHistograms uint = 100
  17. kMaxCommandHistograms uint = 50
  18. kLiteralBlockSwitchCost float64 = 28.1
  19. kCommandBlockSwitchCost float64 = 13.5
  20. kDistanceBlockSwitchCost float64 = 14.6
  21. kLiteralStrideLength uint = 70
  22. kCommandStrideLength uint = 40
  23. kSymbolsPerLiteralHistogram uint = 544
  24. kSymbolsPerCommandHistogram uint = 530
  25. kSymbolsPerDistanceHistogram uint = 544
  26. kMinLengthForBlockSplitting uint = 128
  27. kIterMulForRefining uint = 2
  28. kMinItersForRefining uint = 100
  29. )
  30. func countLiterals(cmds []command) uint {
  31. var total_length uint = 0
  32. /* Count how many we have. */
  33. for i := range cmds {
  34. total_length += uint(cmds[i].insert_len_)
  35. }
  36. return total_length
  37. }
  38. func copyLiteralsToByteArray(cmds []command, data []byte, offset uint, mask uint, literals []byte) {
  39. var pos uint = 0
  40. var from_pos uint = offset & mask
  41. for i := range cmds {
  42. var insert_len uint = uint(cmds[i].insert_len_)
  43. if from_pos+insert_len > mask {
  44. var head_size uint = mask + 1 - from_pos
  45. copy(literals[pos:], data[from_pos:][:head_size])
  46. from_pos = 0
  47. pos += head_size
  48. insert_len -= head_size
  49. }
  50. if insert_len > 0 {
  51. copy(literals[pos:], data[from_pos:][:insert_len])
  52. pos += insert_len
  53. }
  54. from_pos = uint((uint32(from_pos+insert_len) + commandCopyLen(&cmds[i])) & uint32(mask))
  55. }
  56. }
  57. func myRand(seed *uint32) uint32 {
  58. /* Initial seed should be 7. In this case, loop length is (1 << 29). */
  59. *seed *= 16807
  60. return *seed
  61. }
  62. func bitCost(count uint) float64 {
  63. if count == 0 {
  64. return -2.0
  65. } else {
  66. return fastLog2(count)
  67. }
  68. }
  69. const histogramsPerBatch = 64
  70. const clustersPerBatch = 16
  71. func initBlockSplit(self *blockSplit) {
  72. self.num_types = 0
  73. self.num_blocks = 0
  74. self.types = self.types[:0]
  75. self.lengths = self.lengths[:0]
  76. self.types_alloc_size = 0
  77. self.lengths_alloc_size = 0
  78. }
  79. func splitBlock(cmds []command, data []byte, pos uint, mask uint, params *encoderParams, literal_split *blockSplit, insert_and_copy_split *blockSplit, dist_split *blockSplit) {
  80. {
  81. var literals_count uint = countLiterals(cmds)
  82. var literals []byte = make([]byte, literals_count)
  83. /* Create a continuous array of literals. */
  84. copyLiteralsToByteArray(cmds, data, pos, mask, literals)
  85. /* Create the block split on the array of literals.
  86. Literal histograms have alphabet size 256. */
  87. splitByteVectorLiteral(literals, literals_count, kSymbolsPerLiteralHistogram, kMaxLiteralHistograms, kLiteralStrideLength, kLiteralBlockSwitchCost, params, literal_split)
  88. literals = nil
  89. }
  90. {
  91. var insert_and_copy_codes []uint16 = make([]uint16, len(cmds))
  92. /* Compute prefix codes for commands. */
  93. for i := range cmds {
  94. insert_and_copy_codes[i] = cmds[i].cmd_prefix_
  95. }
  96. /* Create the block split on the array of command prefixes. */
  97. splitByteVectorCommand(insert_and_copy_codes, kSymbolsPerCommandHistogram, kMaxCommandHistograms, kCommandStrideLength, kCommandBlockSwitchCost, params, insert_and_copy_split)
  98. /* TODO: reuse for distances? */
  99. insert_and_copy_codes = nil
  100. }
  101. {
  102. var distance_prefixes []uint16 = make([]uint16, len(cmds))
  103. var j uint = 0
  104. /* Create a continuous array of distance prefixes. */
  105. for i := range cmds {
  106. var cmd *command = &cmds[i]
  107. if commandCopyLen(cmd) != 0 && cmd.cmd_prefix_ >= 128 {
  108. distance_prefixes[j] = cmd.dist_prefix_ & 0x3FF
  109. j++
  110. }
  111. }
  112. /* Create the block split on the array of distance prefixes. */
  113. splitByteVectorDistance(distance_prefixes, j, kSymbolsPerDistanceHistogram, kMaxCommandHistograms, kCommandStrideLength, kDistanceBlockSwitchCost, params, dist_split)
  114. distance_prefixes = nil
  115. }
  116. }