package brotli

import 

/* Copyright 2010 Google Inc. All Rights Reserved.

   Distributed under MIT license.
   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/

/* A (forgetful) hash table to the data seen by the compressor, to
   help create backward references to previous data.

   This is a hash map of fixed size (bucket_size_) to a ring buffer of
   fixed size (block_size_). The ring buffer contains the last block_size_
   index positions of the given hash key in the compressed data. */
func (*h5) () uint {
	return 4
}

func (*h5) () uint {
	return 4
}

/* HashBytes is the function that chooses the bucket to place the address in. */
func hashBytesH5( []byte,  int) uint32 {
	var  uint32 = binary.LittleEndian.Uint32() * kHashMul32

	/* The higher bits contain more mixture from the multiplication,
	   so we take our results from there. */
	return uint32( >> uint())
}

type h5 struct {
	hasherCommon
	bucket_size_ uint
	block_size_  uint
	hash_shift_  int
	block_mask_  uint32
	num          []uint16
	buckets      []uint32
}

func ( *h5) ( *encoderParams) {
	.hash_shift_ = 32 - .params.bucket_bits
	.bucket_size_ = uint(1) << uint(.params.bucket_bits)
	.block_size_ = uint(1) << uint(.params.block_bits)
	.block_mask_ = uint32(.block_size_ - 1)
	.num = make([]uint16, .bucket_size_)
	.buckets = make([]uint32, .block_size_*.bucket_size_)
}

func ( *h5) ( bool,  uint,  []byte) {
	var  []uint16 = .num
	var  uint = .bucket_size_ >> 6
	/* Partial preparation is 100 times slower (per socket). */
	if  &&  <=  {
		var  uint
		for  = 0;  < ; ++ {
			var  uint32 = hashBytesH5([:], .hash_shift_)
			[] = 0
		}
	} else {
		for  := 0;  < int(.bucket_size_); ++ {
			[] = 0
		}
	}
}

/* Look at 4 bytes at &data[ix & mask].
   Compute a hash from these, and store the value of ix at that position. */
func ( *h5) ( []byte,  uint,  uint) {
	var  []uint16 = .num
	var  uint32 = hashBytesH5([&:], .hash_shift_)
	var  uint = uint([]) & uint(.block_mask_)
	var  uint =  + uint(<<uint(.params.block_bits))
	.buckets[] = uint32()
	[]++
}

func ( *h5) ( []byte,  uint,  uint,  uint) {
	var  uint
	for  = ;  < ; ++ {
		.Store(, , )
	}
}

func ( *h5) ( uint,  uint,  []byte,  uint) {
	if  >= .HashTypeLength()-1 &&  >= 3 {
		/* Prepare the hashes for three last bytes of the last write.
		   These could not be calculated before, since they require knowledge
		   of both the previous and the current block. */
		.Store(, , -3)
		.Store(, , -2)
		.Store(, , -1)
	}
}

func ( *h5) ( []int) {
	prepareDistanceCache(, .params.num_last_distances_to_check)
}

/* Find a longest backward match of &data[cur_ix] up to the length of
   max_length and stores the position cur_ix in the hash table.

   REQUIRES: PrepareDistanceCacheH5 must be invoked for current distance cache
             values; if this method is invoked repeatedly with the same distance
             cache values, it is enough to invoke PrepareDistanceCacheH5 once.

   Does not look for matches longer than max_length.
   Does not look for matches further away than max_backward.
   Writes the best match into |out|.
   |out|->score is updated only if a better match is found. */
func ( *h5) ( *encoderDictionary,  []byte,  uint,  []int,  uint,  uint,  uint,  uint,  uint,  *hasherSearchResult) {
	var  []uint16 = .num
	var  []uint32 = .buckets
	var  uint =  & 
	var  uint = .score
	var  uint = .score
	var  uint = .len
	var  uint
	var  []uint32
	/* Don't accept a short copy from far away. */
	.len = 0

	.len_code_delta = 0

	/* Try last distance first. */
	for  = 0;  < uint(.params.num_last_distances_to_check); ++ {
		var  uint = uint([])
		var  uint = uint( - )
		if  >=  {
			continue
		}

		if  >  {
			continue
		}

		 &= 

		if + >  || + >  || [+] != [+] {
			continue
		}
		{
			var  uint = findMatchLengthWithLimit([:], [:], )
			if  >= 3 || ( == 2 &&  < 2) {
				/* Comparing for >= 2 does not change the semantics, but just saves for
				   a few unnecessary binary logarithms in backward reference score,
				   since we are not interested in such short matches. */
				var  uint = backwardReferenceScoreUsingLastDistance(uint())
				if  <  {
					if  != 0 {
						 -= backwardReferencePenaltyUsingLastDistance()
					}
					if  <  {
						 = 
						 = uint()
						.len = 
						.distance = 
						.score = 
					}
				}
			}
		}
	}
	{
		var  uint32 = hashBytesH5([:], .hash_shift_)
		 = [<<uint(.params.block_bits):]
		var  uint
		if uint([]) > .block_size_ {
			 = uint([]) - .block_size_
		} else {
			 = 0
		}
		for  = uint([]);  > ; {
			var  uint
			--
			 = uint([uint32()&.block_mask_])
			var  uint =  - 
			if  >  {
				break
			}

			 &= 
			if + >  || + >  || [+] != [+] {
				continue
			}
			{
				var  uint = findMatchLengthWithLimit([:], [:], )
				if  >= 4 {
					/* Comparing for >= 3 does not change the semantics, but just saves
					   for a few unnecessary binary logarithms in backward reference
					   score, since we are not interested in such short matches. */
					var  uint = backwardReferenceScore(uint(), )
					if  <  {
						 = 
						 = uint()
						.len = 
						.distance = 
						.score = 
					}
				}
			}
		}

		[uint32([])&.block_mask_] = uint32()
		[]++
	}

	if  == .score {
		searchInStaticDictionary(, , [:], , +, , , false)
	}
}