package flate

import 

// fastEncL3
type fastEncL3 struct {
	fastGen
	table [1 << 16]tableEntryPrev
}

// Encode uses a similar algorithm to level 2, will check up to two candidates.
func ( *fastEncL3) ( *tokens,  []byte) {
	const (
		            = 12 - 1
		 = 1 + 1 + 
		              = 16
		              = 1 << 
		              = 5
	)

	if debugDeflate && .cur < 0 {
		panic(fmt.Sprint("e.cur < 0: ", .cur))
	}

	// Protect against e.cur wraparound.
	for .cur >= bufferReset {
		if len(.hist) == 0 {
			for  := range .table[:] {
				.table[] = tableEntryPrev{}
			}
			.cur = maxMatchOffset
			break
		}
		// Shift down everything in the table that isn't already too far away.
		 := .cur + int32(len(.hist)) - maxMatchOffset
		for  := range .table[:] {
			 := .table[]
			if .Cur.offset <=  {
				.Cur.offset = 0
			} else {
				.Cur.offset = .Cur.offset - .cur + maxMatchOffset
			}
			if .Prev.offset <=  {
				.Prev.offset = 0
			} else {
				.Prev.offset = .Prev.offset - .cur + maxMatchOffset
			}
			.table[] = 
		}
		.cur = maxMatchOffset
	}

	 := .addBlock()

	// Skip if too small.
	if len() <  {
		// We do not fill the token table.
		// This will be picked up by caller.
		.n = uint16(len())
		return
	}

	// Override src
	 = .hist
	 := 

	// sLimit is when to stop looking for offset/length copies. The inputMargin
	// lets us use a fast path for emitLiteral in the main loop, while we are
	// looking for copies.
	 := int32(len() - )

	// nextEmit is where in src the next emitLiteral should start from.
	 := load6432(, )
	for {
		const  = 7
		 := 
		var  tableEntry
		for {
			 := hashLen(, , )
			 = 
			 =  + 1 + (-)>>
			if  >  {
				goto 
			}
			 := .table[]
			 := load6432(, )

			// Safe offset distance until s + 4...
			 := .cur +  - (maxMatchOffset - 4)
			.table[] = tableEntryPrev{Prev: .Cur, Cur: tableEntry{offset:  + .cur}}

			// Check both candidates
			 = .Cur
			if .offset <  {
				 = 
				// Previous will also be invalid, we have nothing.
				continue
			}

			if uint32() == load3232(, .offset-.cur) {
				if .Prev.offset <  || uint32() != load3232(, .Prev.offset-.cur) {
					break
				}
				// Both match and are valid, pick longest.
				 :=  - (.offset - .cur)
				 :=  - (.Prev.offset - .cur)
				,  := matchLen([+4:], [-+4:]), matchLen([+4:], [-+4:])
				if  >  {
					 = .Prev
				}
				break
			} else {
				// We only check if value mismatches.
				// Offset will always be invalid in other cases.
				 = .Prev
				if .offset >  && uint32() == load3232(, .offset-.cur) {
					break
				}
			}
			 = 
		}

		// Call emitCopy, and then see if another emitCopy could be our next
		// move. Repeat until we find no match for the input immediately after
		// what was consumed by the last emitCopy call.
		//
		// If we exit this loop normally then we need to call emitLiteral next,
		// though we don't yet know how big the literal will be. We handle that
		// by proceeding to the next iteration of the main loop. We also can
		// exit this loop via goto if we get close to exhausting the input.
		for {
			// Invariant: we have a 4-byte match at s, and no need to emit any
			// literal bytes prior to s.

			// Extend the 4-byte match as long as possible.
			//
			 := .offset - .cur
			 := .matchlenLong(+4, +4, ) + 4

			// Extend backwards
			for  > 0 &&  >  && [-1] == [-1] {
				--
				--
				++
			}
			if  <  {
				if false {
					emitLiteral(, [:])
				} else {
					for ,  := range [:] {
						.tokens[.n] = token()
						.litHist[]++
						.n++
					}
				}
			}

			.AddMatchLong(, uint32(--baseMatchOffset))
			 += 
			 = 
			if  >=  {
				 =  + 1
			}

			if  >=  {
				 += 
				// Index first pair after match end.
				if int(+8) < len() &&  > 0 {
					 = load6432(, )
					 := hashLen(, , )
					.table[] = tableEntryPrev{
						Prev: .table[].Cur,
						Cur:  tableEntry{offset: .cur + },
					}
				}
				goto 
			}

			// Store every 5th hash in-between.
			for  :=  -  + 2;  < -5;  += 6 {
				 := hashLen(load6432(, ), , )
				.table[] = tableEntryPrev{
					Prev: .table[].Cur,
					Cur:  tableEntry{offset: .cur + }}
			}
			// We could immediately start working at s now, but to improve
			// compression we first update the hash table at s-2 to s.
			 := load6432(, -2)
			 := hashLen(, , )

			.table[] = tableEntryPrev{
				Prev: .table[].Cur,
				Cur:  tableEntry{offset: .cur +  - 2},
			}
			 >>= 8
			 = hashLen(, , )

			.table[] = tableEntryPrev{
				Prev: .table[].Cur,
				Cur:  tableEntry{offset: .cur +  - 1},
			}
			 >>= 8
			 := hashLen(, , )
			 := .table[]
			 = 
			.table[] = tableEntryPrev{
				Prev: .Cur,
				Cur:  tableEntry{offset:  + .cur},
			}

			// Check both candidates
			 = .Cur
			 := .cur +  - (maxMatchOffset - 4)

			if .offset >  {
				if uint32() == load3232(, .offset-.cur) {
					// Found a match...
					continue
				}
				 = .Prev
				if .offset >  && uint32() == load3232(, .offset-.cur) {
					// Match at prev...
					continue
				}
			}
			 =  >> 8
			++
			break
		}
	}

:
	if int() < len() {
		// If nothing was added, don't encode literals.
		if .n == 0 {
			return
		}

		emitLiteral(, [:])
	}
}