// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flate

import (
	
)

const (
	// tableBits is the number of bits used in the hash table.
	tableBits = 15

	// tableSize is the size of the hash table.
	tableSize = 1 << tableBits

	// hashLongBytes is the number of bytes used for long table hashes.
	hashLongBytes = 7

	// baseMatchOffset is the smallest match offset.
	baseMatchOffset = 1

	// baseMatchLength is the smallest match length per RFC section 3.2.5.
	baseMatchLength = 3

	// maxMatchOffset is the largest match offset.
	maxMatchOffset = 1 << 15

	// allocHistory is the size to preallocate for history.
	allocHistory = maxStoreBlockSize * 5

	// bufferReset is the buffer offset at which the history is reset.
	bufferReset = (1 << 31) - allocHistory - maxStoreBlockSize - 1
)

// fastEncL1 to fastEncL6 provides specialized encoders for levels 1-6
// that each provide a different speed/size/memory strategies.
//
// Level 1: Single small table, 5 byte hashes, sparse indexing.
// Level 2: Single big table, 5 byte hashes, indexing ~ every 2 bytes.
// Level 3: Single medium table, 5 byte hashes, 2 candidates per table entry.
// Level 4: Two tables, 4/7 byte hashes, 1 candidate per table entry.
// Level 5: Two tables, 4/7 byte hashes, 2 candidates per 7-byte table entry.
// Level 6: Two tables, 4/7 byte hashes, full indexing, checks for repeats.
//
// Skipping on contiguous non-matches also decreases as levels go up.

// fastEnc is the interface implemented by the level 1-6 fast encoders.
type fastEnc interface {
	// encode src into dst.
	encode(dst *tokens, src []byte)
	// reset the encoder so matches are not made with previous data.
	reset()
}

// newFastEnc returns a fastEnc encoder for the given compression level (1-6).
func ( int) fastEnc {
	switch  {
	case 1:
		return &fastEncL1{fastGen: fastGen{cur: maxStoreBlockSize}}
	case 2:
		return &fastEncL2{fastGen: fastGen{cur: maxStoreBlockSize}}
	case 3:
		return &fastEncL3{fastGen: fastGen{cur: maxStoreBlockSize}}
	case 4:
		return &fastEncL4{fastGen: fastGen{cur: maxStoreBlockSize}}
	case 5:
		return &fastEncL5{fastGen: fastGen{cur: maxStoreBlockSize}}
	case 6:
		return &fastEncL6{fastGen: fastGen{cur: maxStoreBlockSize}}
	default:
		panic("invalid level specified")
	}
}

// fastGen maintains the table for matches,
// and the previous byte block for level 1 and up.
// This is the generic implementation.
type fastGen struct {
	hist []byte
	cur  int32
}

// addBlock appends src to the history and returns the offset where src starts in e.hist.
func ( *fastGen) ( []byte) int32 {
	// check if we have space already
	if len(.hist)+len() > cap(.hist) {
		if cap(.hist) == 0 {
			.hist = make([]byte, 0, allocHistory)
		} else {
			if cap(.hist) < maxMatchOffset*2 {
				panic("unexpected buffer size")
			}
			// Move down
			 := int32(len(.hist)) - maxMatchOffset
			copy(.hist[0:maxMatchOffset], .hist[:+maxMatchOffset])
			.cur += 
			.hist = .hist[:maxMatchOffset]
		}
	}
	 := int32(len(.hist))
	.hist = append(.hist, ...)
	return 
}

// matchLenLimited returns the match length between offsets s and t in src.
// The maximum length returned is maxMatchLength - 4.
// It is assumed that s > t, that t >= 0 and s < len(src).
func ( *fastGen) (,  int,  []byte) int32 {
	 := [:min(+maxMatchLength-4, len())]
	 := [:]
	return int32(matchLen(, ))
}

// matchLenLong returns the match length between offsets s and t in src.
// It is assumed that s > t, that t >= 0 and s < len(src).
func ( *fastGen) (,  int,  []byte) int32 {
	return int32(matchLen([:], [:]))
}

// reset resets the encoding table to prepare for a new compression stream.
func ( *fastGen) () {
	if cap(.hist) < allocHistory {
		.hist = make([]byte, 0, allocHistory)
	}
	// We offset current position so everything will be out of reach.
	// If we are above the buffer reset it will be cleared anyway since len(hist) == 0.
	if .cur <= bufferReset {
		.cur += maxMatchOffset + int32(len(.hist))
	}
	.hist = .hist[:0]
}

func ( *fastGen) () *fastGen { return  }

// tableEntry stores the offset of a hash match in the input history.
type tableEntry struct {
	offset int32
}

// tableEntryPrev stores the current and previous offsets for a hash entry.
type tableEntryPrev struct {
	cur  tableEntry
	prev tableEntry
}

const (
	prime3bytes = 506832829
	prime4bytes = 2654435761
	prime5bytes = 889523592379
	prime6bytes = 227718039650203
	prime7bytes = 58295818150454627
	prime8bytes = 0xcf1bbcdcb7a56463
)

// hashLen returns a hash of the first n bytes of u, using b output bits.
// It expects 3 <= n <= 8; other values are treated as n == 4.
// The bit length b must be <= 32.
// b and n should be constants in speed-critical use.
func ( uint64, ,  uint8) uint32 {
	switch  {
	case 3:
		return (uint32(<<8) * prime3bytes) >> (32 - )
	case 5:
		return uint32((( << (64 - 40)) * prime5bytes) >> (64 - ))
	case 6:
		return uint32((( << (64 - 48)) * prime6bytes) >> (64 - ))
	case 7:
		return uint32((( << (64 - 56)) * prime7bytes) >> (64 - ))
	case 8:
		return uint32(( * prime8bytes) >> (64 - ))
	default:
		return (uint32() * prime4bytes) >> (32 - )
	}
}

// matchLen returns the maximum common prefix length of a and b.
// a must be the shortest of the two.
func (,  []byte) ( int) {
	 := len()
	for  >= 8 {
		 := loadLE64(, ) ^ loadLE64(, )
		if  != 0 {
			return  + bits.TrailingZeros64()>>3
		}
		 += 8
		 -= 8
	}

	 = [:]
	 = [:]
	 = [:len()]
	for  := range  {
		if [] != [] {
			break
		}
		++
	}
	return 
}