PNG  IHDRxsBIT|d pHYs+tEXtSoftwarewww.inkscape.org<,tEXtComment File Manager

File Manager

Path: /opt/golang/1.22.0/src/index/suffixarray/

Viewing File: sais2.go

// Copyright 2019 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.

// Code generated by go generate; DO NOT EDIT.

package suffixarray

func text_64(text []byte, sa []int64) {
	if int(int64(len(text))) != len(text) || len(text) != len(sa) {
		panic("suffixarray: misuse of text_64")
	}
	sais_8_64(text, 256, sa, make([]int64, 2*256))
}

func sais_8_64(text []byte, textMax int, sa, tmp []int64) {
	if len(sa) != len(text) || len(tmp) < int(textMax) {
		panic("suffixarray: misuse of sais_8_64")
	}

	// Trivial base cases. Sorting 0 or 1 things is easy.
	if len(text) == 0 {
		return
	}
	if len(text) == 1 {
		sa[0] = 0
		return
	}

	// Establish slices indexed by text character
	// holding character frequency and bucket-sort offsets.
	// If there's only enough tmp for one slice,
	// we make it the bucket offsets and recompute
	// the character frequency each time we need it.
	var freq, bucket []int64
	if len(tmp) >= 2*textMax {
		freq, bucket = tmp[:textMax], tmp[textMax:2*textMax]
		freq[0] = -1 // mark as uninitialized
	} else {
		freq, bucket = nil, tmp[:textMax]
	}

	// The SAIS algorithm.
	// Each of these calls makes one scan through sa.
	// See the individual functions for documentation
	// about each's role in the algorithm.
	numLMS := placeLMS_8_64(text, sa, freq, bucket)
	if numLMS <= 1 {
		// 0 or 1 items are already sorted. Do nothing.
	} else {
		induceSubL_8_64(text, sa, freq, bucket)
		induceSubS_8_64(text, sa, freq, bucket)
		length_8_64(text, sa, numLMS)
		maxID := assignID_8_64(text, sa, numLMS)
		if maxID < numLMS {
			map_64(sa, numLMS)
			recurse_64(sa, tmp, numLMS, maxID)
			unmap_8_64(text, sa, numLMS)
		} else {
			// If maxID == numLMS, then each LMS-substring
			// is unique, so the relative ordering of two LMS-suffixes
			// is determined by just the leading LMS-substring.
			// That is, the LMS-suffix sort order matches the
			// (simpler) LMS-substring sort order.
			// Copy the original LMS-substring order into the
			// suffix array destination.
			copy(sa, sa[len(sa)-numLMS:])
		}
		expand_8_64(text, freq, bucket, sa, numLMS)
	}
	induceL_8_64(text, sa, freq, bucket)
	induceS_8_64(text, sa, freq, bucket)

	// Mark for caller that we overwrote tmp.
	tmp[0] = -1
}

func sais_32(text []int32, textMax int, sa, tmp []int32) {
	if len(sa) != len(text) || len(tmp) < int(textMax) {
		panic("suffixarray: misuse of sais_32")
	}

	// Trivial base cases. Sorting 0 or 1 things is easy.
	if len(text) == 0 {
		return
	}
	if len(text) == 1 {
		sa[0] = 0
		return
	}

	// Establish slices indexed by text character
	// holding character frequency and bucket-sort offsets.
	// If there's only enough tmp for one slice,
	// we make it the bucket offsets and recompute
	// the character frequency each time we need it.
	var freq, bucket []int32
	if len(tmp) >= 2*textMax {
		freq, bucket = tmp[:textMax], tmp[textMax:2*textMax]
		freq[0] = -1 // mark as uninitialized
	} else {
		freq, bucket = nil, tmp[:textMax]
	}

	// The SAIS algorithm.
	// Each of these calls makes one scan through sa.
	// See the individual functions for documentation
	// about each's role in the algorithm.
	numLMS := placeLMS_32(text, sa, freq, bucket)
	if numLMS <= 1 {
		// 0 or 1 items are already sorted. Do nothing.
	} else {
		induceSubL_32(text, sa, freq, bucket)
		induceSubS_32(text, sa, freq, bucket)
		length_32(text, sa, numLMS)
		maxID := assignID_32(text, sa, numLMS)
		if maxID < numLMS {
			map_32(sa, numLMS)
			recurse_32(sa, tmp, numLMS, maxID)
			unmap_32(text, sa, numLMS)
		} else {
			// If maxID == numLMS, then each LMS-substring
			// is unique, so the relative ordering of two LMS-suffixes
			// is determined by just the leading LMS-substring.
			// That is, the LMS-suffix sort order matches the
			// (simpler) LMS-substring sort order.
			// Copy the original LMS-substring order into the
			// suffix array destination.
			copy(sa, sa[len(sa)-numLMS:])
		}
		expand_32(text, freq, bucket, sa, numLMS)
	}
	induceL_32(text, sa, freq, bucket)
	induceS_32(text, sa, freq, bucket)

	// Mark for caller that we overwrote tmp.
	tmp[0] = -1
}

func sais_64(text []int64, textMax int, sa, tmp []int64) {
	if len(sa) != len(text) || len(tmp) < int(textMax) {
		panic("suffixarray: misuse of sais_64")
	}

	// Trivial base cases. Sorting 0 or 1 things is easy.
	if len(text) == 0 {
		return
	}
	if len(text) == 1 {
		sa[0] = 0
		return
	}

	// Establish slices indexed by text character
	// holding character frequency and bucket-sort offsets.
	// If there's only enough tmp for one slice,
	// we make it the bucket offsets and recompute
	// the character frequency each time we need it.
	var freq, bucket []int64
	if len(tmp) >= 2*textMax {
		freq, bucket = tmp[:textMax], tmp[textMax:2*textMax]
		freq[0] = -1 // mark as uninitialized
	} else {
		freq, bucket = nil, tmp[:textMax]
	}

	// The SAIS algorithm.
	// Each of these calls makes one scan through sa.
	// See the individual functions for documentation
	// about each's role in the algorithm.
	numLMS := placeLMS_64(text, sa, freq, bucket)
	if numLMS <= 1 {
		// 0 or 1 items are already sorted. Do nothing.
	} else {
		induceSubL_64(text, sa, freq, bucket)
		induceSubS_64(text, sa, freq, bucket)
		length_64(text, sa, numLMS)
		maxID := assignID_64(text, sa, numLMS)
		if maxID < numLMS {
			map_64(sa, numLMS)
			recurse_64(sa, tmp, numLMS, maxID)
			unmap_64(text, sa, numLMS)
		} else {
			// If maxID == numLMS, then each LMS-substring
			// is unique, so the relative ordering of two LMS-suffixes
			// is determined by just the leading LMS-substring.
			// That is, the LMS-suffix sort order matches the
			// (simpler) LMS-substring sort order.
			// Copy the original LMS-substring order into the
			// suffix array destination.
			copy(sa, sa[len(sa)-numLMS:])
		}
		expand_64(text, freq, bucket, sa, numLMS)
	}
	induceL_64(text, sa, freq, bucket)
	induceS_64(text, sa, freq, bucket)

	// Mark for caller that we overwrote tmp.
	tmp[0] = -1
}

func freq_8_64(text []byte, freq, bucket []int64) []int64 {
	if freq != nil && freq[0] >= 0 {
		return freq // already computed
	}
	if freq == nil {
		freq = bucket
	}

	freq = freq[:256] // eliminate bounds check for freq[c] below
	for i := range freq {
		freq[i] = 0
	}
	for _, c := range text {
		freq[c]++
	}
	return freq
}

func freq_32(text []int32, freq, bucket []int32) []int32 {
	if freq != nil && freq[0] >= 0 {
		return freq // already computed
	}
	if freq == nil {
		freq = bucket
	}

	for i := range freq {
		freq[i] = 0
	}
	for _, c := range text {
		freq[c]++
	}
	return freq
}

func freq_64(text []int64, freq, bucket []int64) []int64 {
	if freq != nil && freq[0] >= 0 {
		return freq // already computed
	}
	if freq == nil {
		freq = bucket
	}

	for i := range freq {
		freq[i] = 0
	}
	for _, c := range text {
		freq[c]++
	}
	return freq
}

func bucketMin_8_64(text []byte, freq, bucket []int64) {
	freq = freq_8_64(text, freq, bucket)
	freq = freq[:256]     // establish len(freq) = 256, so 0 ≤ i < 256 below
	bucket = bucket[:256] // eliminate bounds check for bucket[i] below
	total := int64(0)
	for i, n := range freq {
		bucket[i] = total
		total += n
	}
}

func bucketMin_32(text []int32, freq, bucket []int32) {
	freq = freq_32(text, freq, bucket)
	total := int32(0)
	for i, n := range freq {
		bucket[i] = total
		total += n
	}
}

func bucketMin_64(text []int64, freq, bucket []int64) {
	freq = freq_64(text, freq, bucket)
	total := int64(0)
	for i, n := range freq {
		bucket[i] = total
		total += n
	}
}

func bucketMax_8_64(text []byte, freq, bucket []int64) {
	freq = freq_8_64(text, freq, bucket)
	freq = freq[:256]     // establish len(freq) = 256, so 0 ≤ i < 256 below
	bucket = bucket[:256] // eliminate bounds check for bucket[i] below
	total := int64(0)
	for i, n := range freq {
		total += n
		bucket[i] = total
	}
}

func bucketMax_32(text []int32, freq, bucket []int32) {
	freq = freq_32(text, freq, bucket)
	total := int32(0)
	for i, n := range freq {
		total += n
		bucket[i] = total
	}
}

func bucketMax_64(text []int64, freq, bucket []int64) {
	freq = freq_64(text, freq, bucket)
	total := int64(0)
	for i, n := range freq {
		total += n
		bucket[i] = total
	}
}

func placeLMS_8_64(text []byte, sa, freq, bucket []int64) int {
	bucketMax_8_64(text, freq, bucket)

	numLMS := 0
	lastB := int64(-1)
	bucket = bucket[:256] // eliminate bounds check for bucket[c1] below

	// The next stanza of code (until the blank line) loop backward
	// over text, stopping to execute a code body at each position i
	// such that text[i] is an L-character and text[i+1] is an S-character.
	// That is, i+1 is the position of the start of an LMS-substring.
	// These could be hoisted out into a function with a callback,
	// but at a significant speed cost. Instead, we just write these
	// seven lines a few times in this source file. The copies below
	// refer back to the pattern established by this original as the
	// "LMS-substring iterator".
	//
	// In every scan through the text, c0, c1 are successive characters of text.
	// In this backward scan, c0 == text[i] and c1 == text[i+1].
	// By scanning backward, we can keep track of whether the current
	// position is type-S or type-L according to the usual definition:
	//
	//	- position len(text) is type S with text[len(text)] == -1 (the sentinel)
	//	- position i is type S if text[i] < text[i+1], or if text[i] == text[i+1] && i+1 is type S.
	//	- position i is type L if text[i] > text[i+1], or if text[i] == text[i+1] && i+1 is type L.
	//
	// The backward scan lets us maintain the current type,
	// update it when we see c0 != c1, and otherwise leave it alone.
	// We want to identify all S positions with a preceding L.
	// Position len(text) is one such position by definition, but we have
	// nowhere to write it down, so we eliminate it by untruthfully
	// setting isTypeS = false at the start of the loop.
	c0, c1, isTypeS := byte(0), byte(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Bucket the index i+1 for the start of an LMS-substring.
			b := bucket[c1] - 1
			bucket[c1] = b
			sa[b] = int64(i + 1)
			lastB = b
			numLMS++
		}
	}

	// We recorded the LMS-substring starts but really want the ends.
	// Luckily, with two differences, the start indexes and the end indexes are the same.
	// The first difference is that the rightmost LMS-substring's end index is len(text),
	// so the caller must pretend that sa[-1] == len(text), as noted above.
	// The second difference is that the first leftmost LMS-substring start index
	// does not end an earlier LMS-substring, so as an optimization we can omit
	// that leftmost LMS-substring start index (the last one we wrote).
	//
	// Exception: if numLMS <= 1, the caller is not going to bother with
	// the recursion at all and will treat the result as containing LMS-substring starts.
	// In that case, we don't remove the final entry.
	if numLMS > 1 {
		sa[lastB] = 0
	}
	return numLMS
}

func placeLMS_32(text []int32, sa, freq, bucket []int32) int {
	bucketMax_32(text, freq, bucket)

	numLMS := 0
	lastB := int32(-1)

	// The next stanza of code (until the blank line) loop backward
	// over text, stopping to execute a code body at each position i
	// such that text[i] is an L-character and text[i+1] is an S-character.
	// That is, i+1 is the position of the start of an LMS-substring.
	// These could be hoisted out into a function with a callback,
	// but at a significant speed cost. Instead, we just write these
	// seven lines a few times in this source file. The copies below
	// refer back to the pattern established by this original as the
	// "LMS-substring iterator".
	//
	// In every scan through the text, c0, c1 are successive characters of text.
	// In this backward scan, c0 == text[i] and c1 == text[i+1].
	// By scanning backward, we can keep track of whether the current
	// position is type-S or type-L according to the usual definition:
	//
	//	- position len(text) is type S with text[len(text)] == -1 (the sentinel)
	//	- position i is type S if text[i] < text[i+1], or if text[i] == text[i+1] && i+1 is type S.
	//	- position i is type L if text[i] > text[i+1], or if text[i] == text[i+1] && i+1 is type L.
	//
	// The backward scan lets us maintain the current type,
	// update it when we see c0 != c1, and otherwise leave it alone.
	// We want to identify all S positions with a preceding L.
	// Position len(text) is one such position by definition, but we have
	// nowhere to write it down, so we eliminate it by untruthfully
	// setting isTypeS = false at the start of the loop.
	c0, c1, isTypeS := int32(0), int32(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Bucket the index i+1 for the start of an LMS-substring.
			b := bucket[c1] - 1
			bucket[c1] = b
			sa[b] = int32(i + 1)
			lastB = b
			numLMS++
		}
	}

	// We recorded the LMS-substring starts but really want the ends.
	// Luckily, with two differences, the start indexes and the end indexes are the same.
	// The first difference is that the rightmost LMS-substring's end index is len(text),
	// so the caller must pretend that sa[-1] == len(text), as noted above.
	// The second difference is that the first leftmost LMS-substring start index
	// does not end an earlier LMS-substring, so as an optimization we can omit
	// that leftmost LMS-substring start index (the last one we wrote).
	//
	// Exception: if numLMS <= 1, the caller is not going to bother with
	// the recursion at all and will treat the result as containing LMS-substring starts.
	// In that case, we don't remove the final entry.
	if numLMS > 1 {
		sa[lastB] = 0
	}
	return numLMS
}

func placeLMS_64(text []int64, sa, freq, bucket []int64) int {
	bucketMax_64(text, freq, bucket)

	numLMS := 0
	lastB := int64(-1)

	// The next stanza of code (until the blank line) loop backward
	// over text, stopping to execute a code body at each position i
	// such that text[i] is an L-character and text[i+1] is an S-character.
	// That is, i+1 is the position of the start of an LMS-substring.
	// These could be hoisted out into a function with a callback,
	// but at a significant speed cost. Instead, we just write these
	// seven lines a few times in this source file. The copies below
	// refer back to the pattern established by this original as the
	// "LMS-substring iterator".
	//
	// In every scan through the text, c0, c1 are successive characters of text.
	// In this backward scan, c0 == text[i] and c1 == text[i+1].
	// By scanning backward, we can keep track of whether the current
	// position is type-S or type-L according to the usual definition:
	//
	//	- position len(text) is type S with text[len(text)] == -1 (the sentinel)
	//	- position i is type S if text[i] < text[i+1], or if text[i] == text[i+1] && i+1 is type S.
	//	- position i is type L if text[i] > text[i+1], or if text[i] == text[i+1] && i+1 is type L.
	//
	// The backward scan lets us maintain the current type,
	// update it when we see c0 != c1, and otherwise leave it alone.
	// We want to identify all S positions with a preceding L.
	// Position len(text) is one such position by definition, but we have
	// nowhere to write it down, so we eliminate it by untruthfully
	// setting isTypeS = false at the start of the loop.
	c0, c1, isTypeS := int64(0), int64(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Bucket the index i+1 for the start of an LMS-substring.
			b := bucket[c1] - 1
			bucket[c1] = b
			sa[b] = int64(i + 1)
			lastB = b
			numLMS++
		}
	}

	// We recorded the LMS-substring starts but really want the ends.
	// Luckily, with two differences, the start indexes and the end indexes are the same.
	// The first difference is that the rightmost LMS-substring's end index is len(text),
	// so the caller must pretend that sa[-1] == len(text), as noted above.
	// The second difference is that the first leftmost LMS-substring start index
	// does not end an earlier LMS-substring, so as an optimization we can omit
	// that leftmost LMS-substring start index (the last one we wrote).
	//
	// Exception: if numLMS <= 1, the caller is not going to bother with
	// the recursion at all and will treat the result as containing LMS-substring starts.
	// In that case, we don't remove the final entry.
	if numLMS > 1 {
		sa[lastB] = 0
	}
	return numLMS
}

func induceSubL_8_64(text []byte, sa, freq, bucket []int64) {
	// Initialize positions for left side of character buckets.
	bucketMin_8_64(text, freq, bucket)
	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below

	// As we scan the array left-to-right, each sa[i] = j > 0 is a correctly
	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type L.
	// Because j-1 is type L, inserting it into sa now will sort it correctly.
	// But we want to distinguish a j-1 with j-2 of type L from type S.
	// We can process the former but want to leave the latter for the caller.
	// We record the difference by negating j-1 if it is preceded by type S.
	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
	// happen at sa[i´] for some i´ > i, that is, in the portion of sa we have
	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
	// and so on, in sorted but not necessarily adjacent order, until it finds
	// one preceded by an index of type S, at which point it must stop.
	//
	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
	// and we flip sa[i] < 0 to -sa[i], so that the loop finishes with sa containing
	// only the indexes of the leftmost L-type indexes for each LMS-substring.
	//
	// The suffix array sa therefore serves simultaneously as input, output,
	// and a miraculously well-tailored work queue.

	// placeLMS_8_64 left out the implicit entry sa[-1] == len(text),
	// corresponding to the identified type-L index len(text)-1.
	// Process it before the left-to-right scan of sa proper.
	// See body in loop for commentary.
	k := len(text) - 1
	c0, c1 := text[k-1], text[k]
	if c0 < c1 {
		k = -k
	}

	// Cache recently used bucket index:
	// we're processing suffixes in sorted order
	// and accessing buckets indexed by the
	// byte before the sorted order, which still
	// has very good locality.
	// Invariant: b is cached, possibly dirty copy of bucket[cB].
	cB := c1
	b := bucket[cB]
	sa[b] = int64(k)
	b++

	for i := 0; i < len(sa); i++ {
		j := int(sa[i])
		if j == 0 {
			// Skip empty entry.
			continue
		}
		if j < 0 {
			// Leave discovered type-S index for caller.
			sa[i] = int64(-j)
			continue
		}
		sa[i] = 0

		// Index j was on work queue, meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is L-type, queue k for processing later in this loop.
		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
		k := j - 1
		c0, c1 := text[k-1], text[k]
		if c0 < c1 {
			k = -k
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		sa[b] = int64(k)
		b++
	}
}

func induceSubL_32(text []int32, sa, freq, bucket []int32) {
	// Initialize positions for left side of character buckets.
	bucketMin_32(text, freq, bucket)

	// As we scan the array left-to-right, each sa[i] = j > 0 is a correctly
	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type L.
	// Because j-1 is type L, inserting it into sa now will sort it correctly.
	// But we want to distinguish a j-1 with j-2 of type L from type S.
	// We can process the former but want to leave the latter for the caller.
	// We record the difference by negating j-1 if it is preceded by type S.
	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
	// happen at sa[i´] for some i´ > i, that is, in the portion of sa we have
	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
	// and so on, in sorted but not necessarily adjacent order, until it finds
	// one preceded by an index of type S, at which point it must stop.
	//
	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
	// and we flip sa[i] < 0 to -sa[i], so that the loop finishes with sa containing
	// only the indexes of the leftmost L-type indexes for each LMS-substring.
	//
	// The suffix array sa therefore serves simultaneously as input, output,
	// and a miraculously well-tailored work queue.

	// placeLMS_32 left out the implicit entry sa[-1] == len(text),
	// corresponding to the identified type-L index len(text)-1.
	// Process it before the left-to-right scan of sa proper.
	// See body in loop for commentary.
	k := len(text) - 1
	c0, c1 := text[k-1], text[k]
	if c0 < c1 {
		k = -k
	}

	// Cache recently used bucket index:
	// we're processing suffixes in sorted order
	// and accessing buckets indexed by the
	// int32 before the sorted order, which still
	// has very good locality.
	// Invariant: b is cached, possibly dirty copy of bucket[cB].
	cB := c1
	b := bucket[cB]
	sa[b] = int32(k)
	b++

	for i := 0; i < len(sa); i++ {
		j := int(sa[i])
		if j == 0 {
			// Skip empty entry.
			continue
		}
		if j < 0 {
			// Leave discovered type-S index for caller.
			sa[i] = int32(-j)
			continue
		}
		sa[i] = 0

		// Index j was on work queue, meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is L-type, queue k for processing later in this loop.
		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
		k := j - 1
		c0, c1 := text[k-1], text[k]
		if c0 < c1 {
			k = -k
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		sa[b] = int32(k)
		b++
	}
}

func induceSubL_64(text []int64, sa, freq, bucket []int64) {
	// Initialize positions for left side of character buckets.
	bucketMin_64(text, freq, bucket)

	// As we scan the array left-to-right, each sa[i] = j > 0 is a correctly
	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type L.
	// Because j-1 is type L, inserting it into sa now will sort it correctly.
	// But we want to distinguish a j-1 with j-2 of type L from type S.
	// We can process the former but want to leave the latter for the caller.
	// We record the difference by negating j-1 if it is preceded by type S.
	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
	// happen at sa[i´] for some i´ > i, that is, in the portion of sa we have
	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
	// and so on, in sorted but not necessarily adjacent order, until it finds
	// one preceded by an index of type S, at which point it must stop.
	//
	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
	// and we flip sa[i] < 0 to -sa[i], so that the loop finishes with sa containing
	// only the indexes of the leftmost L-type indexes for each LMS-substring.
	//
	// The suffix array sa therefore serves simultaneously as input, output,
	// and a miraculously well-tailored work queue.

	// placeLMS_64 left out the implicit entry sa[-1] == len(text),
	// corresponding to the identified type-L index len(text)-1.
	// Process it before the left-to-right scan of sa proper.
	// See body in loop for commentary.
	k := len(text) - 1
	c0, c1 := text[k-1], text[k]
	if c0 < c1 {
		k = -k
	}

	// Cache recently used bucket index:
	// we're processing suffixes in sorted order
	// and accessing buckets indexed by the
	// int64 before the sorted order, which still
	// has very good locality.
	// Invariant: b is cached, possibly dirty copy of bucket[cB].
	cB := c1
	b := bucket[cB]
	sa[b] = int64(k)
	b++

	for i := 0; i < len(sa); i++ {
		j := int(sa[i])
		if j == 0 {
			// Skip empty entry.
			continue
		}
		if j < 0 {
			// Leave discovered type-S index for caller.
			sa[i] = int64(-j)
			continue
		}
		sa[i] = 0

		// Index j was on work queue, meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is L-type, queue k for processing later in this loop.
		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
		k := j - 1
		c0, c1 := text[k-1], text[k]
		if c0 < c1 {
			k = -k
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		sa[b] = int64(k)
		b++
	}
}

func induceSubS_8_64(text []byte, sa, freq, bucket []int64) {
	// Initialize positions for right side of character buckets.
	bucketMax_8_64(text, freq, bucket)
	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below

	// Analogous to induceSubL_8_64 above,
	// as we scan the array right-to-left, each sa[i] = j > 0 is a correctly
	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type S.
	// Because j-1 is type S, inserting it into sa now will sort it correctly.
	// But we want to distinguish a j-1 with j-2 of type S from type L.
	// We can process the former but want to leave the latter for the caller.
	// We record the difference by negating j-1 if it is preceded by type L.
	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
	// happen at sa[i´] for some i´ < i, that is, in the portion of sa we have
	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
	// and so on, in sorted but not necessarily adjacent order, until it finds
	// one preceded by an index of type L, at which point it must stop.
	// That index (preceded by one of type L) is an LMS-substring start.
	//
	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
	// and we flip sa[i] < 0 to -sa[i] and compact into the top of sa,
	// so that the loop finishes with the top of sa containing exactly
	// the LMS-substring start indexes, sorted by LMS-substring.

	// Cache recently used bucket index:
	cB := byte(0)
	b := bucket[cB]

	top := len(sa)
	for i := len(sa) - 1; i >= 0; i-- {
		j := int(sa[i])
		if j == 0 {
			// Skip empty entry.
			continue
		}
		sa[i] = 0
		if j < 0 {
			// Leave discovered LMS-substring start index for caller.
			top--
			sa[top] = int64(-j)
			continue
		}

		// Index j was on work queue, meaning k := j-1 is S-type,
		// so we can now place k correctly into sa.
		// If k-1 is S-type, queue k for processing later in this loop.
		// If k-1 is L-type (text[k-1] > text[k]), queue -k to save for the caller.
		k := j - 1
		c1 := text[k]
		c0 := text[k-1]
		if c0 > c1 {
			k = -k
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		b--
		sa[b] = int64(k)
	}
}

func induceSubS_32(text []int32, sa, freq, bucket []int32) {
	// Initialize positions for right side of character buckets.
	bucketMax_32(text, freq, bucket)

	// Analogous to induceSubL_32 above,
	// as we scan the array right-to-left, each sa[i] = j > 0 is a correctly
	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type S.
	// Because j-1 is type S, inserting it into sa now will sort it correctly.
	// But we want to distinguish a j-1 with j-2 of type S from type L.
	// We can process the former but want to leave the latter for the caller.
	// We record the difference by negating j-1 if it is preceded by type L.
	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
	// happen at sa[i´] for some i´ < i, that is, in the portion of sa we have
	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
	// and so on, in sorted but not necessarily adjacent order, until it finds
	// one preceded by an index of type L, at which point it must stop.
	// That index (preceded by one of type L) is an LMS-substring start.
	//
	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
	// and we flip sa[i] < 0 to -sa[i] and compact into the top of sa,
	// so that the loop finishes with the top of sa containing exactly
	// the LMS-substring start indexes, sorted by LMS-substring.

	// Cache recently used bucket index:
	cB := int32(0)
	b := bucket[cB]

	top := len(sa)
	for i := len(sa) - 1; i >= 0; i-- {
		j := int(sa[i])
		if j == 0 {
			// Skip empty entry.
			continue
		}
		sa[i] = 0
		if j < 0 {
			// Leave discovered LMS-substring start index for caller.
			top--
			sa[top] = int32(-j)
			continue
		}

		// Index j was on work queue, meaning k := j-1 is S-type,
		// so we can now place k correctly into sa.
		// If k-1 is S-type, queue k for processing later in this loop.
		// If k-1 is L-type (text[k-1] > text[k]), queue -k to save for the caller.
		k := j - 1
		c1 := text[k]
		c0 := text[k-1]
		if c0 > c1 {
			k = -k
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		b--
		sa[b] = int32(k)
	}
}

func induceSubS_64(text []int64, sa, freq, bucket []int64) {
	// Initialize positions for right side of character buckets.
	bucketMax_64(text, freq, bucket)

	// Analogous to induceSubL_64 above,
	// as we scan the array right-to-left, each sa[i] = j > 0 is a correctly
	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type S.
	// Because j-1 is type S, inserting it into sa now will sort it correctly.
	// But we want to distinguish a j-1 with j-2 of type S from type L.
	// We can process the former but want to leave the latter for the caller.
	// We record the difference by negating j-1 if it is preceded by type L.
	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
	// happen at sa[i´] for some i´ < i, that is, in the portion of sa we have
	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
	// and so on, in sorted but not necessarily adjacent order, until it finds
	// one preceded by an index of type L, at which point it must stop.
	// That index (preceded by one of type L) is an LMS-substring start.
	//
	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
	// and we flip sa[i] < 0 to -sa[i] and compact into the top of sa,
	// so that the loop finishes with the top of sa containing exactly
	// the LMS-substring start indexes, sorted by LMS-substring.

	// Cache recently used bucket index:
	cB := int64(0)
	b := bucket[cB]

	top := len(sa)
	for i := len(sa) - 1; i >= 0; i-- {
		j := int(sa[i])
		if j == 0 {
			// Skip empty entry.
			continue
		}
		sa[i] = 0
		if j < 0 {
			// Leave discovered LMS-substring start index for caller.
			top--
			sa[top] = int64(-j)
			continue
		}

		// Index j was on work queue, meaning k := j-1 is S-type,
		// so we can now place k correctly into sa.
		// If k-1 is S-type, queue k for processing later in this loop.
		// If k-1 is L-type (text[k-1] > text[k]), queue -k to save for the caller.
		k := j - 1
		c1 := text[k]
		c0 := text[k-1]
		if c0 > c1 {
			k = -k
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		b--
		sa[b] = int64(k)
	}
}

func length_8_64(text []byte, sa []int64, numLMS int) {
	end := 0 // index of current LMS-substring end (0 indicates final LMS-substring)

	// The encoding of N text bytes into a “length” word
	// adds 1 to each byte, packs them into the bottom
	// N*8 bits of a word, and then bitwise inverts the result.
	// That is, the text sequence A B C (hex 41 42 43)
	// encodes as ^uint64(0x42_43_44).
	// LMS-substrings can never start or end with 0xFF.
	// Adding 1 ensures the encoded byte sequence never
	// starts or ends with 0x00, so that present bytes can be
	// distinguished from zero-padding in the top bits,
	// so the length need not be separately encoded.
	// Inverting the bytes increases the chance that a
	// 4-byte encoding will still be ≥ len(text).
	// In particular, if the first byte is ASCII (<= 0x7E, so +1 <= 0x7F)
	// then the high bit of the inversion will be set,
	// making it clearly not a valid length (it would be a negative one).
	//
	// cx holds the pre-inverted encoding (the packed incremented bytes).
	cx := uint64(0) // byte-only

	// This stanza (until the blank line) is the "LMS-substring iterator",
	// described in placeLMS_8_64 above, with one line added to maintain cx.
	c0, c1, isTypeS := byte(0), byte(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		cx = cx<<8 | uint64(c1+1) // byte-only
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Index j = i+1 is the start of an LMS-substring.
			// Compute length or encoded text to store in sa[j/2].
			j := i + 1
			var code int64
			if end == 0 {
				code = 0
			} else {
				code = int64(end - j)
				if code <= 64/8 && ^cx >= uint64(len(text)) { // byte-only
					code = int64(^cx) // byte-only
				} // byte-only
			}
			sa[j>>1] = code
			end = j + 1
			cx = uint64(c1 + 1) // byte-only
		}
	}
}

func length_32(text []int32, sa []int32, numLMS int) {
	end := 0 // index of current LMS-substring end (0 indicates final LMS-substring)

	// The encoding of N text int32s into a “length” word
	// adds 1 to each int32, packs them into the bottom
	// N*8 bits of a word, and then bitwise inverts the result.
	// That is, the text sequence A B C (hex 41 42 43)
	// encodes as ^uint32(0x42_43_44).
	// LMS-substrings can never start or end with 0xFF.
	// Adding 1 ensures the encoded int32 sequence never
	// starts or ends with 0x00, so that present int32s can be
	// distinguished from zero-padding in the top bits,
	// so the length need not be separately encoded.
	// Inverting the int32s increases the chance that a
	// 4-int32 encoding will still be ≥ len(text).
	// In particular, if the first int32 is ASCII (<= 0x7E, so +1 <= 0x7F)
	// then the high bit of the inversion will be set,
	// making it clearly not a valid length (it would be a negative one).
	//
	// cx holds the pre-inverted encoding (the packed incremented int32s).

	// This stanza (until the blank line) is the "LMS-substring iterator",
	// described in placeLMS_32 above, with one line added to maintain cx.
	c0, c1, isTypeS := int32(0), int32(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Index j = i+1 is the start of an LMS-substring.
			// Compute length or encoded text to store in sa[j/2].
			j := i + 1
			var code int32
			if end == 0 {
				code = 0
			} else {
				code = int32(end - j)
			}
			sa[j>>1] = code
			end = j + 1
		}
	}
}

func length_64(text []int64, sa []int64, numLMS int) {
	end := 0 // index of current LMS-substring end (0 indicates final LMS-substring)

	// The encoding of N text int64s into a “length” word
	// adds 1 to each int64, packs them into the bottom
	// N*8 bits of a word, and then bitwise inverts the result.
	// That is, the text sequence A B C (hex 41 42 43)
	// encodes as ^uint64(0x42_43_44).
	// LMS-substrings can never start or end with 0xFF.
	// Adding 1 ensures the encoded int64 sequence never
	// starts or ends with 0x00, so that present int64s can be
	// distinguished from zero-padding in the top bits,
	// so the length need not be separately encoded.
	// Inverting the int64s increases the chance that a
	// 4-int64 encoding will still be ≥ len(text).
	// In particular, if the first int64 is ASCII (<= 0x7E, so +1 <= 0x7F)
	// then the high bit of the inversion will be set,
	// making it clearly not a valid length (it would be a negative one).
	//
	// cx holds the pre-inverted encoding (the packed incremented int64s).

	// This stanza (until the blank line) is the "LMS-substring iterator",
	// described in placeLMS_64 above, with one line added to maintain cx.
	c0, c1, isTypeS := int64(0), int64(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Index j = i+1 is the start of an LMS-substring.
			// Compute length or encoded text to store in sa[j/2].
			j := i + 1
			var code int64
			if end == 0 {
				code = 0
			} else {
				code = int64(end - j)
			}
			sa[j>>1] = code
			end = j + 1
		}
	}
}

func assignID_8_64(text []byte, sa []int64, numLMS int) int {
	id := 0
	lastLen := int64(-1) // impossible
	lastPos := int64(0)
	for _, j := range sa[len(sa)-numLMS:] {
		// Is the LMS-substring at index j new, or is it the same as the last one we saw?
		n := sa[j/2]
		if n != lastLen {
			goto New
		}
		if uint64(n) >= uint64(len(text)) {
			// “Length” is really encoded full text, and they match.
			goto Same
		}
		{
			// Compare actual texts.
			n := int(n)
			this := text[j:][:n]
			last := text[lastPos:][:n]
			for i := 0; i < n; i++ {
				if this[i] != last[i] {
					goto New
				}
			}
			goto Same
		}
	New:
		id++
		lastPos = j
		lastLen = n
	Same:
		sa[j/2] = int64(id)
	}
	return id
}

func assignID_32(text []int32, sa []int32, numLMS int) int {
	id := 0
	lastLen := int32(-1) // impossible
	lastPos := int32(0)
	for _, j := range sa[len(sa)-numLMS:] {
		// Is the LMS-substring at index j new, or is it the same as the last one we saw?
		n := sa[j/2]
		if n != lastLen {
			goto New
		}
		if uint32(n) >= uint32(len(text)) {
			// “Length” is really encoded full text, and they match.
			goto Same
		}
		{
			// Compare actual texts.
			n := int(n)
			this := text[j:][:n]
			last := text[lastPos:][:n]
			for i := 0; i < n; i++ {
				if this[i] != last[i] {
					goto New
				}
			}
			goto Same
		}
	New:
		id++
		lastPos = j
		lastLen = n
	Same:
		sa[j/2] = int32(id)
	}
	return id
}

func assignID_64(text []int64, sa []int64, numLMS int) int {
	id := 0
	lastLen := int64(-1) // impossible
	lastPos := int64(0)
	for _, j := range sa[len(sa)-numLMS:] {
		// Is the LMS-substring at index j new, or is it the same as the last one we saw?
		n := sa[j/2]
		if n != lastLen {
			goto New
		}
		if uint64(n) >= uint64(len(text)) {
			// “Length” is really encoded full text, and they match.
			goto Same
		}
		{
			// Compare actual texts.
			n := int(n)
			this := text[j:][:n]
			last := text[lastPos:][:n]
			for i := 0; i < n; i++ {
				if this[i] != last[i] {
					goto New
				}
			}
			goto Same
		}
	New:
		id++
		lastPos = j
		lastLen = n
	Same:
		sa[j/2] = int64(id)
	}
	return id
}

func map_64(sa []int64, numLMS int) {
	w := len(sa)
	for i := len(sa) / 2; i >= 0; i-- {
		j := sa[i]
		if j > 0 {
			w--
			sa[w] = j - 1
		}
	}
}

func recurse_64(sa, oldTmp []int64, numLMS, maxID int) {
	dst, saTmp, text := sa[:numLMS], sa[numLMS:len(sa)-numLMS], sa[len(sa)-numLMS:]

	// Set up temporary space for recursive call.
	// We must pass sais_64 a tmp buffer with at least maxID entries.
	//
	// The subproblem is guaranteed to have length at most len(sa)/2,
	// so that sa can hold both the subproblem and its suffix array.
	// Nearly all the time, however, the subproblem has length < len(sa)/3,
	// in which case there is a subproblem-sized middle of sa that
	// we can reuse for temporary space (saTmp).
	// When recurse_64 is called from sais_8_64, oldTmp is length 512
	// (from text_64), and saTmp will typically be much larger, so we'll use saTmp.
	// When deeper recursions come back to recurse_64, now oldTmp is
	// the saTmp from the top-most recursion, it is typically larger than
	// the current saTmp (because the current sa gets smaller and smaller
	// as the recursion gets deeper), and we keep reusing that top-most
	// large saTmp instead of the offered smaller ones.
	//
	// Why is the subproblem length so often just under len(sa)/3?
	// See Nong, Zhang, and Chen, section 3.6 for a plausible explanation.
	// In brief, the len(sa)/2 case would correspond to an SLSLSLSLSLSL pattern
	// in the input, perfect alternation of larger and smaller input bytes.
	// Real text doesn't do that. If each L-type index is randomly followed
	// by either an L-type or S-type index, then half the substrings will
	// be of the form SLS, but the other half will be longer. Of that half,
	// half (a quarter overall) will be SLLS; an eighth will be SLLLS, and so on.
	// Not counting the final S in each (which overlaps the first S in the next),
	// This works out to an average length 2×½ + 3×¼ + 4×⅛ + ... = 3.
	// The space we need is further reduced by the fact that many of the
	// short patterns like SLS will often be the same character sequences
	// repeated throughout the text, reducing maxID relative to numLMS.
	//
	// For short inputs, the averages may not run in our favor, but then we
	// can often fall back to using the length-512 tmp available in the
	// top-most call. (Also a short allocation would not be a big deal.)
	//
	// For pathological inputs, we fall back to allocating a new tmp of length
	// max(maxID, numLMS/2). This level of the recursion needs maxID,
	// and all deeper levels of the recursion will need no more than numLMS/2,
	// so this one allocation is guaranteed to suffice for the entire stack
	// of recursive calls.
	tmp := oldTmp
	if len(tmp) < len(saTmp) {
		tmp = saTmp
	}
	if len(tmp) < numLMS {
		// TestSAIS/forcealloc reaches this code.
		n := maxID
		if n < numLMS/2 {
			n = numLMS / 2
		}
		tmp = make([]int64, n)
	}

	// sais_64 requires that the caller arrange to clear dst,
	// because in general the caller may know dst is
	// freshly-allocated and already cleared. But this one is not.
	for i := range dst {
		dst[i] = 0
	}
	sais_64(text, maxID, dst, tmp)
}

func unmap_8_64(text []byte, sa []int64, numLMS int) {
	unmap := sa[len(sa)-numLMS:]
	j := len(unmap)

	// "LMS-substring iterator" (see placeLMS_8_64 above).
	c0, c1, isTypeS := byte(0), byte(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Populate inverse map.
			j--
			unmap[j] = int64(i + 1)
		}
	}

	// Apply inverse map to subproblem suffix array.
	sa = sa[:numLMS]
	for i := 0; i < len(sa); i++ {
		sa[i] = unmap[sa[i]]
	}
}

func unmap_32(text []int32, sa []int32, numLMS int) {
	unmap := sa[len(sa)-numLMS:]
	j := len(unmap)

	// "LMS-substring iterator" (see placeLMS_32 above).
	c0, c1, isTypeS := int32(0), int32(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Populate inverse map.
			j--
			unmap[j] = int32(i + 1)
		}
	}

	// Apply inverse map to subproblem suffix array.
	sa = sa[:numLMS]
	for i := 0; i < len(sa); i++ {
		sa[i] = unmap[sa[i]]
	}
}

func unmap_64(text []int64, sa []int64, numLMS int) {
	unmap := sa[len(sa)-numLMS:]
	j := len(unmap)

	// "LMS-substring iterator" (see placeLMS_64 above).
	c0, c1, isTypeS := int64(0), int64(0), false
	for i := len(text) - 1; i >= 0; i-- {
		c0, c1 = text[i], c0
		if c0 < c1 {
			isTypeS = true
		} else if c0 > c1 && isTypeS {
			isTypeS = false

			// Populate inverse map.
			j--
			unmap[j] = int64(i + 1)
		}
	}

	// Apply inverse map to subproblem suffix array.
	sa = sa[:numLMS]
	for i := 0; i < len(sa); i++ {
		sa[i] = unmap[sa[i]]
	}
}

func expand_8_64(text []byte, freq, bucket, sa []int64, numLMS int) {
	bucketMax_8_64(text, freq, bucket)
	bucket = bucket[:256] // eliminate bound check for bucket[c] below

	// Loop backward through sa, always tracking
	// the next index to populate from sa[:numLMS].
	// When we get to one, populate it.
	// Zero the rest of the slots; they have dead values in them.
	x := numLMS - 1
	saX := sa[x]
	c := text[saX]
	b := bucket[c] - 1
	bucket[c] = b

	for i := len(sa) - 1; i >= 0; i-- {
		if i != int(b) {
			sa[i] = 0
			continue
		}
		sa[i] = saX

		// Load next entry to put down (if any).
		if x > 0 {
			x--
			saX = sa[x] // TODO bounds check
			c = text[saX]
			b = bucket[c] - 1
			bucket[c] = b
		}
	}
}

func expand_32(text []int32, freq, bucket, sa []int32, numLMS int) {
	bucketMax_32(text, freq, bucket)

	// Loop backward through sa, always tracking
	// the next index to populate from sa[:numLMS].
	// When we get to one, populate it.
	// Zero the rest of the slots; they have dead values in them.
	x := numLMS - 1
	saX := sa[x]
	c := text[saX]
	b := bucket[c] - 1
	bucket[c] = b

	for i := len(sa) - 1; i >= 0; i-- {
		if i != int(b) {
			sa[i] = 0
			continue
		}
		sa[i] = saX

		// Load next entry to put down (if any).
		if x > 0 {
			x--
			saX = sa[x] // TODO bounds check
			c = text[saX]
			b = bucket[c] - 1
			bucket[c] = b
		}
	}
}

func expand_64(text []int64, freq, bucket, sa []int64, numLMS int) {
	bucketMax_64(text, freq, bucket)

	// Loop backward through sa, always tracking
	// the next index to populate from sa[:numLMS].
	// When we get to one, populate it.
	// Zero the rest of the slots; they have dead values in them.
	x := numLMS - 1
	saX := sa[x]
	c := text[saX]
	b := bucket[c] - 1
	bucket[c] = b

	for i := len(sa) - 1; i >= 0; i-- {
		if i != int(b) {
			sa[i] = 0
			continue
		}
		sa[i] = saX

		// Load next entry to put down (if any).
		if x > 0 {
			x--
			saX = sa[x] // TODO bounds check
			c = text[saX]
			b = bucket[c] - 1
			bucket[c] = b
		}
	}
}

func induceL_8_64(text []byte, sa, freq, bucket []int64) {
	// Initialize positions for left side of character buckets.
	bucketMin_8_64(text, freq, bucket)
	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below

	// This scan is similar to the one in induceSubL_8_64 above.
	// That one arranges to clear all but the leftmost L-type indexes.
	// This scan leaves all the L-type indexes and the original S-type
	// indexes, but it negates the positive leftmost L-type indexes
	// (the ones that induceS_8_64 needs to process).

	// expand_8_64 left out the implicit entry sa[-1] == len(text),
	// corresponding to the identified type-L index len(text)-1.
	// Process it before the left-to-right scan of sa proper.
	// See body in loop for commentary.
	k := len(text) - 1
	c0, c1 := text[k-1], text[k]
	if c0 < c1 {
		k = -k
	}

	// Cache recently used bucket index.
	cB := c1
	b := bucket[cB]
	sa[b] = int64(k)
	b++

	for i := 0; i < len(sa); i++ {
		j := int(sa[i])
		if j <= 0 {
			// Skip empty or negated entry (including negated zero).
			continue
		}

		// Index j was on work queue, meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is L-type, queue k for processing later in this loop.
		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
		// If k is zero, k-1 doesn't exist, so we only need to leave it
		// for the caller. The caller can't tell the difference between
		// an empty slot and a non-empty zero, but there's no need
		// to distinguish them anyway: the final suffix array will end up
		// with one zero somewhere, and that will be a real zero.
		k := j - 1
		c1 := text[k]
		if k > 0 {
			if c0 := text[k-1]; c0 < c1 {
				k = -k
			}
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		sa[b] = int64(k)
		b++
	}
}

func induceL_32(text []int32, sa, freq, bucket []int32) {
	// Initialize positions for left side of character buckets.
	bucketMin_32(text, freq, bucket)

	// This scan is similar to the one in induceSubL_32 above.
	// That one arranges to clear all but the leftmost L-type indexes.
	// This scan leaves all the L-type indexes and the original S-type
	// indexes, but it negates the positive leftmost L-type indexes
	// (the ones that induceS_32 needs to process).

	// expand_32 left out the implicit entry sa[-1] == len(text),
	// corresponding to the identified type-L index len(text)-1.
	// Process it before the left-to-right scan of sa proper.
	// See body in loop for commentary.
	k := len(text) - 1
	c0, c1 := text[k-1], text[k]
	if c0 < c1 {
		k = -k
	}

	// Cache recently used bucket index.
	cB := c1
	b := bucket[cB]
	sa[b] = int32(k)
	b++

	for i := 0; i < len(sa); i++ {
		j := int(sa[i])
		if j <= 0 {
			// Skip empty or negated entry (including negated zero).
			continue
		}

		// Index j was on work queue, meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is L-type, queue k for processing later in this loop.
		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
		// If k is zero, k-1 doesn't exist, so we only need to leave it
		// for the caller. The caller can't tell the difference between
		// an empty slot and a non-empty zero, but there's no need
		// to distinguish them anyway: the final suffix array will end up
		// with one zero somewhere, and that will be a real zero.
		k := j - 1
		c1 := text[k]
		if k > 0 {
			if c0 := text[k-1]; c0 < c1 {
				k = -k
			}
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		sa[b] = int32(k)
		b++
	}
}

func induceL_64(text []int64, sa, freq, bucket []int64) {
	// Initialize positions for left side of character buckets.
	bucketMin_64(text, freq, bucket)

	// This scan is similar to the one in induceSubL_64 above.
	// That one arranges to clear all but the leftmost L-type indexes.
	// This scan leaves all the L-type indexes and the original S-type
	// indexes, but it negates the positive leftmost L-type indexes
	// (the ones that induceS_64 needs to process).

	// expand_64 left out the implicit entry sa[-1] == len(text),
	// corresponding to the identified type-L index len(text)-1.
	// Process it before the left-to-right scan of sa proper.
	// See body in loop for commentary.
	k := len(text) - 1
	c0, c1 := text[k-1], text[k]
	if c0 < c1 {
		k = -k
	}

	// Cache recently used bucket index.
	cB := c1
	b := bucket[cB]
	sa[b] = int64(k)
	b++

	for i := 0; i < len(sa); i++ {
		j := int(sa[i])
		if j <= 0 {
			// Skip empty or negated entry (including negated zero).
			continue
		}

		// Index j was on work queue, meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is L-type, queue k for processing later in this loop.
		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
		// If k is zero, k-1 doesn't exist, so we only need to leave it
		// for the caller. The caller can't tell the difference between
		// an empty slot and a non-empty zero, but there's no need
		// to distinguish them anyway: the final suffix array will end up
		// with one zero somewhere, and that will be a real zero.
		k := j - 1
		c1 := text[k]
		if k > 0 {
			if c0 := text[k-1]; c0 < c1 {
				k = -k
			}
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		sa[b] = int64(k)
		b++
	}
}

func induceS_8_64(text []byte, sa, freq, bucket []int64) {
	// Initialize positions for right side of character buckets.
	bucketMax_8_64(text, freq, bucket)
	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below

	cB := byte(0)
	b := bucket[cB]

	for i := len(sa) - 1; i >= 0; i-- {
		j := int(sa[i])
		if j >= 0 {
			// Skip non-flagged entry.
			// (This loop can't see an empty entry; 0 means the real zero index.)
			continue
		}

		// Negative j is a work queue entry; rewrite to positive j for final suffix array.
		j = -j
		sa[i] = int64(j)

		// Index j was on work queue (encoded as -j but now decoded),
		// meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is S-type, queue -k for processing later in this loop.
		// If k-1 is L-type (text[k-1] > text[k]), queue k to save for the caller.
		// If k is zero, k-1 doesn't exist, so we only need to leave it
		// for the caller.
		k := j - 1
		c1 := text[k]
		if k > 0 {
			if c0 := text[k-1]; c0 <= c1 {
				k = -k
			}
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		b--
		sa[b] = int64(k)
	}
}

func induceS_32(text []int32, sa, freq, bucket []int32) {
	// Initialize positions for right side of character buckets.
	bucketMax_32(text, freq, bucket)

	cB := int32(0)
	b := bucket[cB]

	for i := len(sa) - 1; i >= 0; i-- {
		j := int(sa[i])
		if j >= 0 {
			// Skip non-flagged entry.
			// (This loop can't see an empty entry; 0 means the real zero index.)
			continue
		}

		// Negative j is a work queue entry; rewrite to positive j for final suffix array.
		j = -j
		sa[i] = int32(j)

		// Index j was on work queue (encoded as -j but now decoded),
		// meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is S-type, queue -k for processing later in this loop.
		// If k-1 is L-type (text[k-1] > text[k]), queue k to save for the caller.
		// If k is zero, k-1 doesn't exist, so we only need to leave it
		// for the caller.
		k := j - 1
		c1 := text[k]
		if k > 0 {
			if c0 := text[k-1]; c0 <= c1 {
				k = -k
			}
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		b--
		sa[b] = int32(k)
	}
}

func induceS_64(text []int64, sa, freq, bucket []int64) {
	// Initialize positions for right side of character buckets.
	bucketMax_64(text, freq, bucket)

	cB := int64(0)
	b := bucket[cB]

	for i := len(sa) - 1; i >= 0; i-- {
		j := int(sa[i])
		if j >= 0 {
			// Skip non-flagged entry.
			// (This loop can't see an empty entry; 0 means the real zero index.)
			continue
		}

		// Negative j is a work queue entry; rewrite to positive j for final suffix array.
		j = -j
		sa[i] = int64(j)

		// Index j was on work queue (encoded as -j but now decoded),
		// meaning k := j-1 is L-type,
		// so we can now place k correctly into sa.
		// If k-1 is S-type, queue -k for processing later in this loop.
		// If k-1 is L-type (text[k-1] > text[k]), queue k to save for the caller.
		// If k is zero, k-1 doesn't exist, so we only need to leave it
		// for the caller.
		k := j - 1
		c1 := text[k]
		if k > 0 {
			if c0 := text[k-1]; c0 <= c1 {
				k = -k
			}
		}

		if cB != c1 {
			bucket[cB] = b
			cB = c1
			b = bucket[cB]
		}
		b--
		sa[b] = int64(k)
	}
}
b IDATxytVսϓ22 A@IR :hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-EIENT ;@xT.i%-X}SvS5.r/UHz^_$-W"w)Ɗ/@Z &IoX P$K}JzX:;` &, ŋui,e6mX ԵrKb1ԗ)DADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADA݀!I*]R;I2$eZ#ORZSrr6mteffu*((Pu'v{DIߔ4^pIm'77WEEE;vƎ4-$]'RI{\I&G :IHJ DWBB=\WR޽m o$K(V9ABB.}jѢv`^?IOȅ} ڶmG}T#FJ`56$-ھ}FI&v;0(h;Б38CӧOWf!;A i:F_m9s&|q%=#wZprrrla A &P\\СC[A#! {olF} `E2}MK/vV)i{4BffV\|ۭX`b@kɶ@%i$K z5zhmX[IXZ` 'b%$r5M4º/l ԃߖxhʔ)[@=} K6IM}^5k㏷݆z ΗÿO:gdGBmyT/@+Vɶ纽z񕏵l.y޴it뭷zV0[Y^>Wsqs}\/@$(T7f.InݺiR$푔n.~?H))\ZRW'Mo~v Ov6oԃxz! S,&xm/yɞԟ?'uaSѽb,8GלKboi&3t7Y,)JJ c[nzӳdE&KsZLӄ I?@&%ӟ۶mSMMњ0iؐSZ,|J+N ~,0A0!5%Q-YQQa3}$_vVrf9f?S8`zDADADADADADADADADAdqP,تmMmg1V?rSI꒟]u|l RCyEf٢9 jURbztѰ!m5~tGj2DhG*{H9)꒟ר3:(+3\?/;TUݭʴ~S6lڧUJ*i$d(#=Yݺd{,p|3B))q:vN0Y.jkק6;SɶVzHJJЀ-utѹսk>QUU\޲~]fFnK?&ߡ5b=z9)^|u_k-[y%ZNU6 7Mi:]ۦtk[n X(e6Bb."8cۭ|~teuuw|ήI-5"~Uk;ZicEmN/:]M> cQ^uiƞ??Ңpc#TUU3UakNwA`:Y_V-8.KKfRitv޲* 9S6ֿj,ՃNOMߤ]z^fOh|<>@Å5 _/Iu?{SY4hK/2]4%it5q]GGe2%iR| W&f*^]??vq[LgE_3f}Fxu~}qd-ږFxu~I N>\;͗O֊:̗WJ@BhW=y|GgwܷH_NY?)Tdi'?խwhlmQi !SUUsw4kӺe4rfxu-[nHtMFj}H_u~w>)oV}(T'ebʒv3_[+vn@Ȭ\S}ot}w=kHFnxg S 0eޢm~l}uqZfFoZuuEg `zt~? b;t%>WTkķh[2eG8LIWx,^\thrl^Ϊ{=dž<}qV@ ⠨Wy^LF_>0UkDuʫuCs$)Iv:IK;6ֲ4{^6եm+l3>݆uM 9u?>Zc }g~qhKwڭeFMM~pМuqǿz6Tb@8@Y|jx](^]gf}M"tG -w.@vOqh~/HII`S[l.6nØXL9vUcOoB\xoǤ'T&IǍQw_wpv[kmO{w~>#=P1Pɞa-we:iǏlHo׈꒟f9SzH?+shk%Fs:qVhqY`jvO'ρ?PyX3lх]˾uV{ݞ]1,MzYNW~̈́ joYn}ȚF߾׮mS]F z+EDxm/d{F{-W-4wY듏:??_gPf ^3ecg ҵs8R2מz@TANGj)}CNi/R~}c:5{!ZHӋӾ6}T]G]7W6^n 9*,YqOZj:P?Q DFL|?-^.Ɵ7}fFh׶xe2Pscz1&5\cn[=Vn[ĶE鎀uˌd3GII k;lNmشOuuRVfBE]ۣeӶu :X-[(er4~LHi6:Ѻ@ԅrST0trk%$Č0ez" *z"T/X9|8.C5Feg}CQ%͞ˣJvL/?j^h&9xF`њZ(&yF&Iݻfg#W;3^{Wo^4'vV[[K';+mӍִ]AC@W?1^{එyh +^]fm~iԵ]AB@WTk̏t uR?l.OIHiYyԶ]Aˀ7c:q}ힽaf6Z~қm(+sK4{^6}T*UUu]n.:kx{:2 _m=sAߤU@?Z-Vކеz왍Nэ{|5 pڶn b p-@sPg]0G7fy-M{GCF'%{4`=$-Ge\ eU:m+Zt'WjO!OAF@ik&t݆ϥ_ e}=]"Wz_.͜E3leWFih|t-wZۍ-uw=6YN{6|} |*={Ѽn.S.z1zjۻTH]흾 DuDvmvK.`V]yY~sI@t?/ϓ. m&["+P?MzovVЫG3-GRR[(!!\_,^%?v@ҵő m`Y)tem8GMx.))A]Y i`ViW`?^~!S#^+ѽGZj?Vģ0.))A꨷lzL*]OXrY`DBBLOj{-MH'ii-ϰ ok7^ )쭡b]UXSְmռY|5*cֽk0B7镹%ڽP#8nȎq}mJr23_>lE5$iwui+ H~F`IjƵ@q \ @#qG0".0" l`„.0! ,AQHN6qzkKJ#o;`Xv2>,tێJJ7Z/*A .@fفjMzkg @TvZH3Zxu6Ra'%O?/dQ5xYkU]Rֽkق@DaS^RSּ5|BeHNN͘p HvcYcC5:y #`οb;z2.!kr}gUWkyZn=f Pvsn3p~;4p˚=ē~NmI] ¾ 0lH[_L hsh_ғߤc_њec)g7VIZ5yrgk̞W#IjӪv>՞y睝M8[|]\շ8M6%|@PZڨI-m>=k='aiRo-x?>Q.}`Ȏ:Wsmu u > .@,&;+!!˱tﭧDQwRW\vF\~Q7>spYw$%A~;~}6¾ g&if_=j,v+UL1(tWake:@Ș>j$Gq2t7S?vL|]u/ .(0E6Mk6hiۺzښOrifޱxm/Gx> Lal%%~{lBsR4*}{0Z/tNIɚpV^#Lf:u@k#RSu =S^ZyuR/.@n&΃z~B=0eg뺆#,Þ[B/?H uUf7y Wy}Bwegל`Wh(||`l`.;Ws?V@"c:iɍL֯PGv6zctM̠':wuW;d=;EveD}9J@B(0iհ bvP1{\P&G7D޴Iy_$-Qjm~Yrr&]CDv%bh|Yzni_ˆR;kg}nJOIIwyuL}{ЌNj}:+3Y?:WJ/N+Rzd=hb;dj͒suݔ@NKMԄ jqzC5@y°hL m;*5ezᕏ=ep XL n?מ:r`۵tŤZ|1v`V뽧_csج'ߤ%oTuumk%%%h)uy]Nk[n 'b2 l.=͜E%gf$[c;s:V-͞WߤWh-j7]4=F-X]>ZLSi[Y*We;Zan(ӇW|e(HNNP5[= r4tP &0<pc#`vTNV GFqvTi*Tyam$ߏWyE*VJKMTfFw>'$-ؽ.Ho.8c"@DADADADADADADADADA~j*֘,N;Pi3599h=goضLgiJ5փy~}&Zd9p֚ e:|hL``b/d9p? fgg+%%hMgXosج, ΩOl0Zh=xdjLmhݻoO[g_l,8a]٭+ӧ0$I]c]:粹:Teꢢ"5a^Kgh,&= =՟^߶“ߢE ܹS J}I%:8 IDAT~,9/ʃPW'Mo}zNƍ쨓zPbNZ~^z=4mswg;5 Y~SVMRXUյڱRf?s:w ;6H:ºi5-maM&O3;1IKeamZh͛7+##v+c ~u~ca]GnF'ټL~PPPbn voC4R,ӟgg %hq}@#M4IÇ Oy^xMZx ) yOw@HkN˖-Sǎmb]X@n+i͖!++K3gd\$mt$^YfJ\8PRF)77Wא!Cl$i:@@_oG I{$# 8磌ŋ91A (Im7֭>}ߴJq7ޗt^ -[ԩSj*}%]&' -ɓ'ꫯVzzvB#;a 7@GxI{j޼ƌ.LÇWBB7`O"I$/@R @eee@۷>}0,ɒ2$53Xs|cS~rpTYYY} kHc %&k.], @ADADADADADADADADA@lT<%''*Lo^={رc5h %$+CnܸQ3fҥK}vUVVs9G R,_{xˇ3o߾;TTTd}馛]uuuG~iԩ@4bnvmvfϞ /Peeeq}}za I~,誫{UWW뮻}_~YƍSMMMYχ֝waw\ďcxꩧtEƍկ_?۷5@u?1kNׯWzz/wy>}zj3 k(ٺuq_Zvf̘:~ ABQ&r|!%KҥKgԞ={<_X-z !CyFUUz~ ABQIIIjݺW$UXXDٳZ~ ABQƍecW$<(~<RSSvZujjjԧOZQu@4 8m&&&jԩg$ď1h ͟?_{768@g =@`)))5o6m3)ѣƌJ;wҿUTT /KZR{~a=@0o<*狔iFɶ[ˎ;T]]OX@?K.ۈxN pppppppppppppppppPfl߾] ,{ァk۶mڿo5BTӦMӴiӴ|r DB2e|An!Dy'tkΝ[A $***t5' "!駟oaDnΝ:t֭[gDШQ06qD;@ x M6v(PiizmZ4ew"@̴ixf [~-Fٱc&IZ2|n!?$@{[HTɏ#@hȎI# _m(F /6Z3z'\r,r!;w2Z3j=~GY7"I$iI.p_"?pN`y DD?: _  Gÿab7J !Bx@0 Bo cG@`1C[@0G @`0C_u V1 aCX>W ` | `!<S `"<. `#c`?cAC4 ?c p#~@0?:08&_MQ1J h#?/`7;I  q 7a wQ A 1 Hp !#<8/#@1Ul7=S=K.4Z?E_$i@!1!E4?`P_  @Bă10#: "aU,xbFY1 [n|n #'vEH:`xb #vD4Y hi.i&EΖv#O H4IŶ}:Ikh @tZRF#(tXҙzZ ?I3l7q@õ|ۍ1,GpuY Ꮿ@hJv#xxk$ v#9 5 }_$c S#=+"K{F*m7`#%H:NRSp6I?sIՖ{Ap$I$I:QRv2$Z @UJ*$]<FO4IENDB`