Source file src/index/suffixarray/sais2.go

Documentation: index/suffixarray

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Code generated by go generate; DO NOT EDIT.
     6  
     7  package suffixarray
     8  
     9  func text_64(text []byte, sa []int64) {
    10  	if int(int64(len(text))) != len(text) || len(text) != len(sa) {
    11  		panic("suffixarray: misuse of text_64")
    12  	}
    13  	sais_8_64(text, 256, sa, make([]int64, 2*256))
    14  }
    15  
    16  func sais_8_64(text []byte, textMax int, sa, tmp []int64) {
    17  	if len(sa) != len(text) || len(tmp) < int(textMax) {
    18  		panic("suffixarray: misuse of sais_8_64")
    19  	}
    20  
    21  	// Trivial base cases. Sorting 0 or 1 things is easy.
    22  	if len(text) == 0 {
    23  		return
    24  	}
    25  	if len(text) == 1 {
    26  		sa[0] = 0
    27  		return
    28  	}
    29  
    30  	// Establish slices indexed by text character
    31  	// holding character frequency and bucket-sort offsets.
    32  	// If there's only enough tmp for one slice,
    33  	// we make it the bucket offsets and recompute
    34  	// the character frequency each time we need it.
    35  	var freq, bucket []int64
    36  	if len(tmp) >= 2*textMax {
    37  		freq, bucket = tmp[:textMax], tmp[textMax:2*textMax]
    38  		freq[0] = -1 // mark as uninitialized
    39  	} else {
    40  		freq, bucket = nil, tmp[:textMax]
    41  	}
    42  
    43  	// The SAIS algorithm.
    44  	// Each of these calls makes one scan through sa.
    45  	// See the individual functions for documentation
    46  	// about each's role in the algorithm.
    47  	numLMS := placeLMS_8_64(text, sa, freq, bucket)
    48  	if numLMS <= 1 {
    49  		// 0 or 1 items are already sorted. Do nothing.
    50  	} else {
    51  		induceSubL_8_64(text, sa, freq, bucket)
    52  		induceSubS_8_64(text, sa, freq, bucket)
    53  		length_8_64(text, sa, numLMS)
    54  		maxID := assignID_8_64(text, sa, numLMS)
    55  		if maxID < numLMS {
    56  			map_64(sa, numLMS)
    57  			recurse_64(sa, tmp, numLMS, maxID)
    58  			unmap_8_64(text, sa, numLMS)
    59  		} else {
    60  			// If maxID == numLMS, then each LMS-substring
    61  			// is unique, so the relative ordering of two LMS-suffixes
    62  			// is determined by just the leading LMS-substring.
    63  			// That is, the LMS-suffix sort order matches the
    64  			// (simpler) LMS-substring sort order.
    65  			// Copy the original LMS-substring order into the
    66  			// suffix array destination.
    67  			copy(sa, sa[len(sa)-numLMS:])
    68  		}
    69  		expand_8_64(text, freq, bucket, sa, numLMS)
    70  	}
    71  	induceL_8_64(text, sa, freq, bucket)
    72  	induceS_8_64(text, sa, freq, bucket)
    73  
    74  	// Mark for caller that we overwrote tmp.
    75  	tmp[0] = -1
    76  }
    77  
    78  func sais_32(text []int32, textMax int, sa, tmp []int32) {
    79  	if len(sa) != len(text) || len(tmp) < int(textMax) {
    80  		panic("suffixarray: misuse of sais_32")
    81  	}
    82  
    83  	// Trivial base cases. Sorting 0 or 1 things is easy.
    84  	if len(text) == 0 {
    85  		return
    86  	}
    87  	if len(text) == 1 {
    88  		sa[0] = 0
    89  		return
    90  	}
    91  
    92  	// Establish slices indexed by text character
    93  	// holding character frequency and bucket-sort offsets.
    94  	// If there's only enough tmp for one slice,
    95  	// we make it the bucket offsets and recompute
    96  	// the character frequency each time we need it.
    97  	var freq, bucket []int32
    98  	if len(tmp) >= 2*textMax {
    99  		freq, bucket = tmp[:textMax], tmp[textMax:2*textMax]
   100  		freq[0] = -1 // mark as uninitialized
   101  	} else {
   102  		freq, bucket = nil, tmp[:textMax]
   103  	}
   104  
   105  	// The SAIS algorithm.
   106  	// Each of these calls makes one scan through sa.
   107  	// See the individual functions for documentation
   108  	// about each's role in the algorithm.
   109  	numLMS := placeLMS_32(text, sa, freq, bucket)
   110  	if numLMS <= 1 {
   111  		// 0 or 1 items are already sorted. Do nothing.
   112  	} else {
   113  		induceSubL_32(text, sa, freq, bucket)
   114  		induceSubS_32(text, sa, freq, bucket)
   115  		length_32(text, sa, numLMS)
   116  		maxID := assignID_32(text, sa, numLMS)
   117  		if maxID < numLMS {
   118  			map_32(sa, numLMS)
   119  			recurse_32(sa, tmp, numLMS, maxID)
   120  			unmap_32(text, sa, numLMS)
   121  		} else {
   122  			// If maxID == numLMS, then each LMS-substring
   123  			// is unique, so the relative ordering of two LMS-suffixes
   124  			// is determined by just the leading LMS-substring.
   125  			// That is, the LMS-suffix sort order matches the
   126  			// (simpler) LMS-substring sort order.
   127  			// Copy the original LMS-substring order into the
   128  			// suffix array destination.
   129  			copy(sa, sa[len(sa)-numLMS:])
   130  		}
   131  		expand_32(text, freq, bucket, sa, numLMS)
   132  	}
   133  	induceL_32(text, sa, freq, bucket)
   134  	induceS_32(text, sa, freq, bucket)
   135  
   136  	// Mark for caller that we overwrote tmp.
   137  	tmp[0] = -1
   138  }
   139  
   140  func sais_64(text []int64, textMax int, sa, tmp []int64) {
   141  	if len(sa) != len(text) || len(tmp) < int(textMax) {
   142  		panic("suffixarray: misuse of sais_64")
   143  	}
   144  
   145  	// Trivial base cases. Sorting 0 or 1 things is easy.
   146  	if len(text) == 0 {
   147  		return
   148  	}
   149  	if len(text) == 1 {
   150  		sa[0] = 0
   151  		return
   152  	}
   153  
   154  	// Establish slices indexed by text character
   155  	// holding character frequency and bucket-sort offsets.
   156  	// If there's only enough tmp for one slice,
   157  	// we make it the bucket offsets and recompute
   158  	// the character frequency each time we need it.
   159  	var freq, bucket []int64
   160  	if len(tmp) >= 2*textMax {
   161  		freq, bucket = tmp[:textMax], tmp[textMax:2*textMax]
   162  		freq[0] = -1 // mark as uninitialized
   163  	} else {
   164  		freq, bucket = nil, tmp[:textMax]
   165  	}
   166  
   167  	// The SAIS algorithm.
   168  	// Each of these calls makes one scan through sa.
   169  	// See the individual functions for documentation
   170  	// about each's role in the algorithm.
   171  	numLMS := placeLMS_64(text, sa, freq, bucket)
   172  	if numLMS <= 1 {
   173  		// 0 or 1 items are already sorted. Do nothing.
   174  	} else {
   175  		induceSubL_64(text, sa, freq, bucket)
   176  		induceSubS_64(text, sa, freq, bucket)
   177  		length_64(text, sa, numLMS)
   178  		maxID := assignID_64(text, sa, numLMS)
   179  		if maxID < numLMS {
   180  			map_64(sa, numLMS)
   181  			recurse_64(sa, tmp, numLMS, maxID)
   182  			unmap_64(text, sa, numLMS)
   183  		} else {
   184  			// If maxID == numLMS, then each LMS-substring
   185  			// is unique, so the relative ordering of two LMS-suffixes
   186  			// is determined by just the leading LMS-substring.
   187  			// That is, the LMS-suffix sort order matches the
   188  			// (simpler) LMS-substring sort order.
   189  			// Copy the original LMS-substring order into the
   190  			// suffix array destination.
   191  			copy(sa, sa[len(sa)-numLMS:])
   192  		}
   193  		expand_64(text, freq, bucket, sa, numLMS)
   194  	}
   195  	induceL_64(text, sa, freq, bucket)
   196  	induceS_64(text, sa, freq, bucket)
   197  
   198  	// Mark for caller that we overwrote tmp.
   199  	tmp[0] = -1
   200  }
   201  
   202  func freq_8_64(text []byte, freq, bucket []int64) []int64 {
   203  	if freq != nil && freq[0] >= 0 {
   204  		return freq // already computed
   205  	}
   206  	if freq == nil {
   207  		freq = bucket
   208  	}
   209  
   210  	freq = freq[:256] // eliminate bounds check for freq[c] below
   211  	for i := range freq {
   212  		freq[i] = 0
   213  	}
   214  	for _, c := range text {
   215  		freq[c]++
   216  	}
   217  	return freq
   218  }
   219  
   220  func freq_32(text []int32, freq, bucket []int32) []int32 {
   221  	if freq != nil && freq[0] >= 0 {
   222  		return freq // already computed
   223  	}
   224  	if freq == nil {
   225  		freq = bucket
   226  	}
   227  
   228  	for i := range freq {
   229  		freq[i] = 0
   230  	}
   231  	for _, c := range text {
   232  		freq[c]++
   233  	}
   234  	return freq
   235  }
   236  
   237  func freq_64(text []int64, freq, bucket []int64) []int64 {
   238  	if freq != nil && freq[0] >= 0 {
   239  		return freq // already computed
   240  	}
   241  	if freq == nil {
   242  		freq = bucket
   243  	}
   244  
   245  	for i := range freq {
   246  		freq[i] = 0
   247  	}
   248  	for _, c := range text {
   249  		freq[c]++
   250  	}
   251  	return freq
   252  }
   253  
   254  func bucketMin_8_64(text []byte, freq, bucket []int64) {
   255  	freq = freq_8_64(text, freq, bucket)
   256  	freq = freq[:256]     // establish len(freq) = 256, so 0 ≤ i < 256 below
   257  	bucket = bucket[:256] // eliminate bounds check for bucket[i] below
   258  	total := int64(0)
   259  	for i, n := range freq {
   260  		bucket[i] = total
   261  		total += n
   262  	}
   263  }
   264  
   265  func bucketMin_32(text []int32, freq, bucket []int32) {
   266  	freq = freq_32(text, freq, bucket)
   267  	total := int32(0)
   268  	for i, n := range freq {
   269  		bucket[i] = total
   270  		total += n
   271  	}
   272  }
   273  
   274  func bucketMin_64(text []int64, freq, bucket []int64) {
   275  	freq = freq_64(text, freq, bucket)
   276  	total := int64(0)
   277  	for i, n := range freq {
   278  		bucket[i] = total
   279  		total += n
   280  	}
   281  }
   282  
   283  func bucketMax_8_64(text []byte, freq, bucket []int64) {
   284  	freq = freq_8_64(text, freq, bucket)
   285  	freq = freq[:256]     // establish len(freq) = 256, so 0 ≤ i < 256 below
   286  	bucket = bucket[:256] // eliminate bounds check for bucket[i] below
   287  	total := int64(0)
   288  	for i, n := range freq {
   289  		total += n
   290  		bucket[i] = total
   291  	}
   292  }
   293  
   294  func bucketMax_32(text []int32, freq, bucket []int32) {
   295  	freq = freq_32(text, freq, bucket)
   296  	total := int32(0)
   297  	for i, n := range freq {
   298  		total += n
   299  		bucket[i] = total
   300  	}
   301  }
   302  
   303  func bucketMax_64(text []int64, freq, bucket []int64) {
   304  	freq = freq_64(text, freq, bucket)
   305  	total := int64(0)
   306  	for i, n := range freq {
   307  		total += n
   308  		bucket[i] = total
   309  	}
   310  }
   311  
   312  func placeLMS_8_64(text []byte, sa, freq, bucket []int64) int {
   313  	bucketMax_8_64(text, freq, bucket)
   314  
   315  	numLMS := 0
   316  	lastB := int64(-1)
   317  	bucket = bucket[:256] // eliminate bounds check for bucket[c1] below
   318  
   319  	// The next stanza of code (until the blank line) loop backward
   320  	// over text, stopping to execute a code body at each position i
   321  	// such that text[i] is an L-character and text[i+1] is an S-character.
   322  	// That is, i+1 is the position of the start of an LMS-substring.
   323  	// These could be hoisted out into a function with a callback,
   324  	// but at a significant speed cost. Instead, we just write these
   325  	// seven lines a few times in this source file. The copies below
   326  	// refer back to the pattern established by this original as the
   327  	// "LMS-substring iterator".
   328  	//
   329  	// In every scan through the text, c0, c1 are successive characters of text.
   330  	// In this backward scan, c0 == text[i] and c1 == text[i+1].
   331  	// By scanning backward, we can keep track of whether the current
   332  	// position is type-S or type-L according to the usual definition:
   333  	//
   334  	//	- position len(text) is type S with text[len(text)] == -1 (the sentinel)
   335  	//	- position i is type S if text[i] < text[i+1], or if text[i] == text[i+1] && i+1 is type S.
   336  	//	- position i is type L if text[i] > text[i+1], or if text[i] == text[i+1] && i+1 is type L.
   337  	//
   338  	// The backward scan lets us maintain the current type,
   339  	// update it when we see c0 != c1, and otherwise leave it alone.
   340  	// We want to identify all S positions with a preceding L.
   341  	// Position len(text) is one such position by definition, but we have
   342  	// nowhere to write it down, so we eliminate it by untruthfully
   343  	// setting isTypeS = false at the start of the loop.
   344  	c0, c1, isTypeS := byte(0), byte(0), false
   345  	for i := len(text) - 1; i >= 0; i-- {
   346  		c0, c1 = text[i], c0
   347  		if c0 < c1 {
   348  			isTypeS = true
   349  		} else if c0 > c1 && isTypeS {
   350  			isTypeS = false
   351  
   352  			// Bucket the index i+1 for the start of an LMS-substring.
   353  			b := bucket[c1] - 1
   354  			bucket[c1] = b
   355  			sa[b] = int64(i + 1)
   356  			lastB = b
   357  			numLMS++
   358  		}
   359  	}
   360  
   361  	// We recorded the LMS-substring starts but really want the ends.
   362  	// Luckily, with two differences, the start indexes and the end indexes are the same.
   363  	// The first difference is that the rightmost LMS-substring's end index is len(text),
   364  	// so the caller must pretend that sa[-1] == len(text), as noted above.
   365  	// The second difference is that the first leftmost LMS-substring start index
   366  	// does not end an earlier LMS-substring, so as an optimization we can omit
   367  	// that leftmost LMS-substring start index (the last one we wrote).
   368  	//
   369  	// Exception: if numLMS <= 1, the caller is not going to bother with
   370  	// the recursion at all and will treat the result as containing LMS-substring starts.
   371  	// In that case, we don't remove the final entry.
   372  	if numLMS > 1 {
   373  		sa[lastB] = 0
   374  	}
   375  	return numLMS
   376  }
   377  
   378  func placeLMS_32(text []int32, sa, freq, bucket []int32) int {
   379  	bucketMax_32(text, freq, bucket)
   380  
   381  	numLMS := 0
   382  	lastB := int32(-1)
   383  
   384  	// The next stanza of code (until the blank line) loop backward
   385  	// over text, stopping to execute a code body at each position i
   386  	// such that text[i] is an L-character and text[i+1] is an S-character.
   387  	// That is, i+1 is the position of the start of an LMS-substring.
   388  	// These could be hoisted out into a function with a callback,
   389  	// but at a significant speed cost. Instead, we just write these
   390  	// seven lines a few times in this source file. The copies below
   391  	// refer back to the pattern established by this original as the
   392  	// "LMS-substring iterator".
   393  	//
   394  	// In every scan through the text, c0, c1 are successive characters of text.
   395  	// In this backward scan, c0 == text[i] and c1 == text[i+1].
   396  	// By scanning backward, we can keep track of whether the current
   397  	// position is type-S or type-L according to the usual definition:
   398  	//
   399  	//	- position len(text) is type S with text[len(text)] == -1 (the sentinel)
   400  	//	- position i is type S if text[i] < text[i+1], or if text[i] == text[i+1] && i+1 is type S.
   401  	//	- position i is type L if text[i] > text[i+1], or if text[i] == text[i+1] && i+1 is type L.
   402  	//
   403  	// The backward scan lets us maintain the current type,
   404  	// update it when we see c0 != c1, and otherwise leave it alone.
   405  	// We want to identify all S positions with a preceding L.
   406  	// Position len(text) is one such position by definition, but we have
   407  	// nowhere to write it down, so we eliminate it by untruthfully
   408  	// setting isTypeS = false at the start of the loop.
   409  	c0, c1, isTypeS := int32(0), int32(0), false
   410  	for i := len(text) - 1; i >= 0; i-- {
   411  		c0, c1 = text[i], c0
   412  		if c0 < c1 {
   413  			isTypeS = true
   414  		} else if c0 > c1 && isTypeS {
   415  			isTypeS = false
   416  
   417  			// Bucket the index i+1 for the start of an LMS-substring.
   418  			b := bucket[c1] - 1
   419  			bucket[c1] = b
   420  			sa[b] = int32(i + 1)
   421  			lastB = b
   422  			numLMS++
   423  		}
   424  	}
   425  
   426  	// We recorded the LMS-substring starts but really want the ends.
   427  	// Luckily, with two differences, the start indexes and the end indexes are the same.
   428  	// The first difference is that the rightmost LMS-substring's end index is len(text),
   429  	// so the caller must pretend that sa[-1] == len(text), as noted above.
   430  	// The second difference is that the first leftmost LMS-substring start index
   431  	// does not end an earlier LMS-substring, so as an optimization we can omit
   432  	// that leftmost LMS-substring start index (the last one we wrote).
   433  	//
   434  	// Exception: if numLMS <= 1, the caller is not going to bother with
   435  	// the recursion at all and will treat the result as containing LMS-substring starts.
   436  	// In that case, we don't remove the final entry.
   437  	if numLMS > 1 {
   438  		sa[lastB] = 0
   439  	}
   440  	return numLMS
   441  }
   442  
   443  func placeLMS_64(text []int64, sa, freq, bucket []int64) int {
   444  	bucketMax_64(text, freq, bucket)
   445  
   446  	numLMS := 0
   447  	lastB := int64(-1)
   448  
   449  	// The next stanza of code (until the blank line) loop backward
   450  	// over text, stopping to execute a code body at each position i
   451  	// such that text[i] is an L-character and text[i+1] is an S-character.
   452  	// That is, i+1 is the position of the start of an LMS-substring.
   453  	// These could be hoisted out into a function with a callback,
   454  	// but at a significant speed cost. Instead, we just write these
   455  	// seven lines a few times in this source file. The copies below
   456  	// refer back to the pattern established by this original as the
   457  	// "LMS-substring iterator".
   458  	//
   459  	// In every scan through the text, c0, c1 are successive characters of text.
   460  	// In this backward scan, c0 == text[i] and c1 == text[i+1].
   461  	// By scanning backward, we can keep track of whether the current
   462  	// position is type-S or type-L according to the usual definition:
   463  	//
   464  	//	- position len(text) is type S with text[len(text)] == -1 (the sentinel)
   465  	//	- position i is type S if text[i] < text[i+1], or if text[i] == text[i+1] && i+1 is type S.
   466  	//	- position i is type L if text[i] > text[i+1], or if text[i] == text[i+1] && i+1 is type L.
   467  	//
   468  	// The backward scan lets us maintain the current type,
   469  	// update it when we see c0 != c1, and otherwise leave it alone.
   470  	// We want to identify all S positions with a preceding L.
   471  	// Position len(text) is one such position by definition, but we have
   472  	// nowhere to write it down, so we eliminate it by untruthfully
   473  	// setting isTypeS = false at the start of the loop.
   474  	c0, c1, isTypeS := int64(0), int64(0), false
   475  	for i := len(text) - 1; i >= 0; i-- {
   476  		c0, c1 = text[i], c0
   477  		if c0 < c1 {
   478  			isTypeS = true
   479  		} else if c0 > c1 && isTypeS {
   480  			isTypeS = false
   481  
   482  			// Bucket the index i+1 for the start of an LMS-substring.
   483  			b := bucket[c1] - 1
   484  			bucket[c1] = b
   485  			sa[b] = int64(i + 1)
   486  			lastB = b
   487  			numLMS++
   488  		}
   489  	}
   490  
   491  	// We recorded the LMS-substring starts but really want the ends.
   492  	// Luckily, with two differences, the start indexes and the end indexes are the same.
   493  	// The first difference is that the rightmost LMS-substring's end index is len(text),
   494  	// so the caller must pretend that sa[-1] == len(text), as noted above.
   495  	// The second difference is that the first leftmost LMS-substring start index
   496  	// does not end an earlier LMS-substring, so as an optimization we can omit
   497  	// that leftmost LMS-substring start index (the last one we wrote).
   498  	//
   499  	// Exception: if numLMS <= 1, the caller is not going to bother with
   500  	// the recursion at all and will treat the result as containing LMS-substring starts.
   501  	// In that case, we don't remove the final entry.
   502  	if numLMS > 1 {
   503  		sa[lastB] = 0
   504  	}
   505  	return numLMS
   506  }
   507  
   508  func induceSubL_8_64(text []byte, sa, freq, bucket []int64) {
   509  	// Initialize positions for left side of character buckets.
   510  	bucketMin_8_64(text, freq, bucket)
   511  	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below
   512  
   513  	// As we scan the array left-to-right, each sa[i] = j > 0 is a correctly
   514  	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type L.
   515  	// Because j-1 is type L, inserting it into sa now will sort it correctly.
   516  	// But we want to distinguish a j-1 with j-2 of type L from type S.
   517  	// We can process the former but want to leave the latter for the caller.
   518  	// We record the difference by negating j-1 if it is preceded by type S.
   519  	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
   520  	// happen at sa[i´] for some i´ > i, that is, in the portion of sa we have
   521  	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
   522  	// and so on, in sorted but not necessarily adjacent order, until it finds
   523  	// one preceded by an index of type S, at which point it must stop.
   524  	//
   525  	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
   526  	// and we flip sa[i] < 0 to -sa[i], so that the loop finishes with sa containing
   527  	// only the indexes of the leftmost L-type indexes for each LMS-substring.
   528  	//
   529  	// The suffix array sa therefore serves simultaneously as input, output,
   530  	// and a miraculously well-tailored work queue.
   531  
   532  	// placeLMS_8_64 left out the implicit entry sa[-1] == len(text),
   533  	// corresponding to the identified type-L index len(text)-1.
   534  	// Process it before the left-to-right scan of sa proper.
   535  	// See body in loop for commentary.
   536  	k := len(text) - 1
   537  	c0, c1 := text[k-1], text[k]
   538  	if c0 < c1 {
   539  		k = -k
   540  	}
   541  
   542  	// Cache recently used bucket index:
   543  	// we're processing suffixes in sorted order
   544  	// and accessing buckets indexed by the
   545  	// byte before the sorted order, which still
   546  	// has very good locality.
   547  	// Invariant: b is cached, possibly dirty copy of bucket[cB].
   548  	cB := c1
   549  	b := bucket[cB]
   550  	sa[b] = int64(k)
   551  	b++
   552  
   553  	for i := 0; i < len(sa); i++ {
   554  		j := int(sa[i])
   555  		if j == 0 {
   556  			// Skip empty entry.
   557  			continue
   558  		}
   559  		if j < 0 {
   560  			// Leave discovered type-S index for caller.
   561  			sa[i] = int64(-j)
   562  			continue
   563  		}
   564  		sa[i] = 0
   565  
   566  		// Index j was on work queue, meaning k := j-1 is L-type,
   567  		// so we can now place k correctly into sa.
   568  		// If k-1 is L-type, queue k for processing later in this loop.
   569  		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
   570  		k := j - 1
   571  		c0, c1 := text[k-1], text[k]
   572  		if c0 < c1 {
   573  			k = -k
   574  		}
   575  
   576  		if cB != c1 {
   577  			bucket[cB] = b
   578  			cB = c1
   579  			b = bucket[cB]
   580  		}
   581  		sa[b] = int64(k)
   582  		b++
   583  	}
   584  }
   585  
   586  func induceSubL_32(text []int32, sa, freq, bucket []int32) {
   587  	// Initialize positions for left side of character buckets.
   588  	bucketMin_32(text, freq, bucket)
   589  
   590  	// As we scan the array left-to-right, each sa[i] = j > 0 is a correctly
   591  	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type L.
   592  	// Because j-1 is type L, inserting it into sa now will sort it correctly.
   593  	// But we want to distinguish a j-1 with j-2 of type L from type S.
   594  	// We can process the former but want to leave the latter for the caller.
   595  	// We record the difference by negating j-1 if it is preceded by type S.
   596  	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
   597  	// happen at sa[i´] for some i´ > i, that is, in the portion of sa we have
   598  	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
   599  	// and so on, in sorted but not necessarily adjacent order, until it finds
   600  	// one preceded by an index of type S, at which point it must stop.
   601  	//
   602  	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
   603  	// and we flip sa[i] < 0 to -sa[i], so that the loop finishes with sa containing
   604  	// only the indexes of the leftmost L-type indexes for each LMS-substring.
   605  	//
   606  	// The suffix array sa therefore serves simultaneously as input, output,
   607  	// and a miraculously well-tailored work queue.
   608  
   609  	// placeLMS_32 left out the implicit entry sa[-1] == len(text),
   610  	// corresponding to the identified type-L index len(text)-1.
   611  	// Process it before the left-to-right scan of sa proper.
   612  	// See body in loop for commentary.
   613  	k := len(text) - 1
   614  	c0, c1 := text[k-1], text[k]
   615  	if c0 < c1 {
   616  		k = -k
   617  	}
   618  
   619  	// Cache recently used bucket index:
   620  	// we're processing suffixes in sorted order
   621  	// and accessing buckets indexed by the
   622  	// int32 before the sorted order, which still
   623  	// has very good locality.
   624  	// Invariant: b is cached, possibly dirty copy of bucket[cB].
   625  	cB := c1
   626  	b := bucket[cB]
   627  	sa[b] = int32(k)
   628  	b++
   629  
   630  	for i := 0; i < len(sa); i++ {
   631  		j := int(sa[i])
   632  		if j == 0 {
   633  			// Skip empty entry.
   634  			continue
   635  		}
   636  		if j < 0 {
   637  			// Leave discovered type-S index for caller.
   638  			sa[i] = int32(-j)
   639  			continue
   640  		}
   641  		sa[i] = 0
   642  
   643  		// Index j was on work queue, meaning k := j-1 is L-type,
   644  		// so we can now place k correctly into sa.
   645  		// If k-1 is L-type, queue k for processing later in this loop.
   646  		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
   647  		k := j - 1
   648  		c0, c1 := text[k-1], text[k]
   649  		if c0 < c1 {
   650  			k = -k
   651  		}
   652  
   653  		if cB != c1 {
   654  			bucket[cB] = b
   655  			cB = c1
   656  			b = bucket[cB]
   657  		}
   658  		sa[b] = int32(k)
   659  		b++
   660  	}
   661  }
   662  
   663  func induceSubL_64(text []int64, sa, freq, bucket []int64) {
   664  	// Initialize positions for left side of character buckets.
   665  	bucketMin_64(text, freq, bucket)
   666  
   667  	// As we scan the array left-to-right, each sa[i] = j > 0 is a correctly
   668  	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type L.
   669  	// Because j-1 is type L, inserting it into sa now will sort it correctly.
   670  	// But we want to distinguish a j-1 with j-2 of type L from type S.
   671  	// We can process the former but want to leave the latter for the caller.
   672  	// We record the difference by negating j-1 if it is preceded by type S.
   673  	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
   674  	// happen at sa[i´] for some i´ > i, that is, in the portion of sa we have
   675  	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
   676  	// and so on, in sorted but not necessarily adjacent order, until it finds
   677  	// one preceded by an index of type S, at which point it must stop.
   678  	//
   679  	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
   680  	// and we flip sa[i] < 0 to -sa[i], so that the loop finishes with sa containing
   681  	// only the indexes of the leftmost L-type indexes for each LMS-substring.
   682  	//
   683  	// The suffix array sa therefore serves simultaneously as input, output,
   684  	// and a miraculously well-tailored work queue.
   685  
   686  	// placeLMS_64 left out the implicit entry sa[-1] == len(text),
   687  	// corresponding to the identified type-L index len(text)-1.
   688  	// Process it before the left-to-right scan of sa proper.
   689  	// See body in loop for commentary.
   690  	k := len(text) - 1
   691  	c0, c1 := text[k-1], text[k]
   692  	if c0 < c1 {
   693  		k = -k
   694  	}
   695  
   696  	// Cache recently used bucket index:
   697  	// we're processing suffixes in sorted order
   698  	// and accessing buckets indexed by the
   699  	// int64 before the sorted order, which still
   700  	// has very good locality.
   701  	// Invariant: b is cached, possibly dirty copy of bucket[cB].
   702  	cB := c1
   703  	b := bucket[cB]
   704  	sa[b] = int64(k)
   705  	b++
   706  
   707  	for i := 0; i < len(sa); i++ {
   708  		j := int(sa[i])
   709  		if j == 0 {
   710  			// Skip empty entry.
   711  			continue
   712  		}
   713  		if j < 0 {
   714  			// Leave discovered type-S index for caller.
   715  			sa[i] = int64(-j)
   716  			continue
   717  		}
   718  		sa[i] = 0
   719  
   720  		// Index j was on work queue, meaning k := j-1 is L-type,
   721  		// so we can now place k correctly into sa.
   722  		// If k-1 is L-type, queue k for processing later in this loop.
   723  		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
   724  		k := j - 1
   725  		c0, c1 := text[k-1], text[k]
   726  		if c0 < c1 {
   727  			k = -k
   728  		}
   729  
   730  		if cB != c1 {
   731  			bucket[cB] = b
   732  			cB = c1
   733  			b = bucket[cB]
   734  		}
   735  		sa[b] = int64(k)
   736  		b++
   737  	}
   738  }
   739  
   740  func induceSubS_8_64(text []byte, sa, freq, bucket []int64) {
   741  	// Initialize positions for right side of character buckets.
   742  	bucketMax_8_64(text, freq, bucket)
   743  	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below
   744  
   745  	// Analogous to induceSubL_8_64 above,
   746  	// as we scan the array right-to-left, each sa[i] = j > 0 is a correctly
   747  	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type S.
   748  	// Because j-1 is type S, inserting it into sa now will sort it correctly.
   749  	// But we want to distinguish a j-1 with j-2 of type S from type L.
   750  	// We can process the former but want to leave the latter for the caller.
   751  	// We record the difference by negating j-1 if it is preceded by type L.
   752  	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
   753  	// happen at sa[i´] for some i´ < i, that is, in the portion of sa we have
   754  	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
   755  	// and so on, in sorted but not necessarily adjacent order, until it finds
   756  	// one preceded by an index of type L, at which point it must stop.
   757  	// That index (preceded by one of type L) is an LMS-substring start.
   758  	//
   759  	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
   760  	// and we flip sa[i] < 0 to -sa[i] and compact into the top of sa,
   761  	// so that the loop finishes with the top of sa containing exactly
   762  	// the LMS-substring start indexes, sorted by LMS-substring.
   763  
   764  	// Cache recently used bucket index:
   765  	cB := byte(0)
   766  	b := bucket[cB]
   767  
   768  	top := len(sa)
   769  	for i := len(sa) - 1; i >= 0; i-- {
   770  		j := int(sa[i])
   771  		if j == 0 {
   772  			// Skip empty entry.
   773  			continue
   774  		}
   775  		sa[i] = 0
   776  		if j < 0 {
   777  			// Leave discovered LMS-substring start index for caller.
   778  			top--
   779  			sa[top] = int64(-j)
   780  			continue
   781  		}
   782  
   783  		// Index j was on work queue, meaning k := j-1 is S-type,
   784  		// so we can now place k correctly into sa.
   785  		// If k-1 is S-type, queue k for processing later in this loop.
   786  		// If k-1 is L-type (text[k-1] > text[k]), queue -k to save for the caller.
   787  		k := j - 1
   788  		c1 := text[k]
   789  		c0 := text[k-1]
   790  		if c0 > c1 {
   791  			k = -k
   792  		}
   793  
   794  		if cB != c1 {
   795  			bucket[cB] = b
   796  			cB = c1
   797  			b = bucket[cB]
   798  		}
   799  		b--
   800  		sa[b] = int64(k)
   801  	}
   802  }
   803  
   804  func induceSubS_32(text []int32, sa, freq, bucket []int32) {
   805  	// Initialize positions for right side of character buckets.
   806  	bucketMax_32(text, freq, bucket)
   807  
   808  	// Analogous to induceSubL_32 above,
   809  	// as we scan the array right-to-left, each sa[i] = j > 0 is a correctly
   810  	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type S.
   811  	// Because j-1 is type S, inserting it into sa now will sort it correctly.
   812  	// But we want to distinguish a j-1 with j-2 of type S from type L.
   813  	// We can process the former but want to leave the latter for the caller.
   814  	// We record the difference by negating j-1 if it is preceded by type L.
   815  	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
   816  	// happen at sa[i´] for some i´ < i, that is, in the portion of sa we have
   817  	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
   818  	// and so on, in sorted but not necessarily adjacent order, until it finds
   819  	// one preceded by an index of type L, at which point it must stop.
   820  	// That index (preceded by one of type L) is an LMS-substring start.
   821  	//
   822  	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
   823  	// and we flip sa[i] < 0 to -sa[i] and compact into the top of sa,
   824  	// so that the loop finishes with the top of sa containing exactly
   825  	// the LMS-substring start indexes, sorted by LMS-substring.
   826  
   827  	// Cache recently used bucket index:
   828  	cB := int32(0)
   829  	b := bucket[cB]
   830  
   831  	top := len(sa)
   832  	for i := len(sa) - 1; i >= 0; i-- {
   833  		j := int(sa[i])
   834  		if j == 0 {
   835  			// Skip empty entry.
   836  			continue
   837  		}
   838  		sa[i] = 0
   839  		if j < 0 {
   840  			// Leave discovered LMS-substring start index for caller.
   841  			top--
   842  			sa[top] = int32(-j)
   843  			continue
   844  		}
   845  
   846  		// Index j was on work queue, meaning k := j-1 is S-type,
   847  		// so we can now place k correctly into sa.
   848  		// If k-1 is S-type, queue k for processing later in this loop.
   849  		// If k-1 is L-type (text[k-1] > text[k]), queue -k to save for the caller.
   850  		k := j - 1
   851  		c1 := text[k]
   852  		c0 := text[k-1]
   853  		if c0 > c1 {
   854  			k = -k
   855  		}
   856  
   857  		if cB != c1 {
   858  			bucket[cB] = b
   859  			cB = c1
   860  			b = bucket[cB]
   861  		}
   862  		b--
   863  		sa[b] = int32(k)
   864  	}
   865  }
   866  
   867  func induceSubS_64(text []int64, sa, freq, bucket []int64) {
   868  	// Initialize positions for right side of character buckets.
   869  	bucketMax_64(text, freq, bucket)
   870  
   871  	// Analogous to induceSubL_64 above,
   872  	// as we scan the array right-to-left, each sa[i] = j > 0 is a correctly
   873  	// sorted suffix array entry (for text[j:]) for which we know that j-1 is type S.
   874  	// Because j-1 is type S, inserting it into sa now will sort it correctly.
   875  	// But we want to distinguish a j-1 with j-2 of type S from type L.
   876  	// We can process the former but want to leave the latter for the caller.
   877  	// We record the difference by negating j-1 if it is preceded by type L.
   878  	// Either way, the insertion (into the text[j-1] bucket) is guaranteed to
   879  	// happen at sa[i´] for some i´ < i, that is, in the portion of sa we have
   880  	// yet to scan. A single pass therefore sees indexes j, j-1, j-2, j-3,
   881  	// and so on, in sorted but not necessarily adjacent order, until it finds
   882  	// one preceded by an index of type L, at which point it must stop.
   883  	// That index (preceded by one of type L) is an LMS-substring start.
   884  	//
   885  	// As we scan through the array, we clear the worked entries (sa[i] > 0) to zero,
   886  	// and we flip sa[i] < 0 to -sa[i] and compact into the top of sa,
   887  	// so that the loop finishes with the top of sa containing exactly
   888  	// the LMS-substring start indexes, sorted by LMS-substring.
   889  
   890  	// Cache recently used bucket index:
   891  	cB := int64(0)
   892  	b := bucket[cB]
   893  
   894  	top := len(sa)
   895  	for i := len(sa) - 1; i >= 0; i-- {
   896  		j := int(sa[i])
   897  		if j == 0 {
   898  			// Skip empty entry.
   899  			continue
   900  		}
   901  		sa[i] = 0
   902  		if j < 0 {
   903  			// Leave discovered LMS-substring start index for caller.
   904  			top--
   905  			sa[top] = int64(-j)
   906  			continue
   907  		}
   908  
   909  		// Index j was on work queue, meaning k := j-1 is S-type,
   910  		// so we can now place k correctly into sa.
   911  		// If k-1 is S-type, queue k for processing later in this loop.
   912  		// If k-1 is L-type (text[k-1] > text[k]), queue -k to save for the caller.
   913  		k := j - 1
   914  		c1 := text[k]
   915  		c0 := text[k-1]
   916  		if c0 > c1 {
   917  			k = -k
   918  		}
   919  
   920  		if cB != c1 {
   921  			bucket[cB] = b
   922  			cB = c1
   923  			b = bucket[cB]
   924  		}
   925  		b--
   926  		sa[b] = int64(k)
   927  	}
   928  }
   929  
   930  func length_8_64(text []byte, sa []int64, numLMS int) {
   931  	end := 0 // index of current LMS-substring end (0 indicates final LMS-substring)
   932  
   933  	// The encoding of N text bytes into a “length” word
   934  	// adds 1 to each byte, packs them into the bottom
   935  	// N*8 bits of a word, and then bitwise inverts the result.
   936  	// That is, the text sequence A B C (hex 41 42 43)
   937  	// encodes as ^uint64(0x42_43_44).
   938  	// LMS-substrings can never start or end with 0xFF.
   939  	// Adding 1 ensures the encoded byte sequence never
   940  	// starts or ends with 0x00, so that present bytes can be
   941  	// distinguished from zero-padding in the top bits,
   942  	// so the length need not be separately encoded.
   943  	// Inverting the bytes increases the chance that a
   944  	// 4-byte encoding will still be ≥ len(text).
   945  	// In particular, if the first byte is ASCII (<= 0x7E, so +1 <= 0x7F)
   946  	// then the high bit of the inversion will be set,
   947  	// making it clearly not a valid length (it would be a negative one).
   948  	//
   949  	// cx holds the pre-inverted encoding (the packed incremented bytes).
   950  	cx := uint64(0) // byte-only
   951  
   952  	// This stanza (until the blank line) is the "LMS-substring iterator",
   953  	// described in placeLMS_8_64 above, with one line added to maintain cx.
   954  	c0, c1, isTypeS := byte(0), byte(0), false
   955  	for i := len(text) - 1; i >= 0; i-- {
   956  		c0, c1 = text[i], c0
   957  		cx = cx<<8 | uint64(c1+1) // byte-only
   958  		if c0 < c1 {
   959  			isTypeS = true
   960  		} else if c0 > c1 && isTypeS {
   961  			isTypeS = false
   962  
   963  			// Index j = i+1 is the start of an LMS-substring.
   964  			// Compute length or encoded text to store in sa[j/2].
   965  			j := i + 1
   966  			var code int64
   967  			if end == 0 {
   968  				code = 0
   969  			} else {
   970  				code = int64(end - j)
   971  				if code <= 64/8 && ^cx >= uint64(len(text)) { // byte-only
   972  					code = int64(^cx) // byte-only
   973  				} // byte-only
   974  			}
   975  			sa[j>>1] = code
   976  			end = j + 1
   977  			cx = uint64(c1 + 1) // byte-only
   978  		}
   979  	}
   980  }
   981  
   982  func length_32(text []int32, sa []int32, numLMS int) {
   983  	end := 0 // index of current LMS-substring end (0 indicates final LMS-substring)
   984  
   985  	// The encoding of N text int32s into a “length” word
   986  	// adds 1 to each int32, packs them into the bottom
   987  	// N*8 bits of a word, and then bitwise inverts the result.
   988  	// That is, the text sequence A B C (hex 41 42 43)
   989  	// encodes as ^uint32(0x42_43_44).
   990  	// LMS-substrings can never start or end with 0xFF.
   991  	// Adding 1 ensures the encoded int32 sequence never
   992  	// starts or ends with 0x00, so that present int32s can be
   993  	// distinguished from zero-padding in the top bits,
   994  	// so the length need not be separately encoded.
   995  	// Inverting the int32s increases the chance that a
   996  	// 4-int32 encoding will still be ≥ len(text).
   997  	// In particular, if the first int32 is ASCII (<= 0x7E, so +1 <= 0x7F)
   998  	// then the high bit of the inversion will be set,
   999  	// making it clearly not a valid length (it would be a negative one).
  1000  	//
  1001  	// cx holds the pre-inverted encoding (the packed incremented int32s).
  1002  
  1003  	// This stanza (until the blank line) is the "LMS-substring iterator",
  1004  	// described in placeLMS_32 above, with one line added to maintain cx.
  1005  	c0, c1, isTypeS := int32(0), int32(0), false
  1006  	for i := len(text) - 1; i >= 0; i-- {
  1007  		c0, c1 = text[i], c0
  1008  		if c0 < c1 {
  1009  			isTypeS = true
  1010  		} else if c0 > c1 && isTypeS {
  1011  			isTypeS = false
  1012  
  1013  			// Index j = i+1 is the start of an LMS-substring.
  1014  			// Compute length or encoded text to store in sa[j/2].
  1015  			j := i + 1
  1016  			var code int32
  1017  			if end == 0 {
  1018  				code = 0
  1019  			} else {
  1020  				code = int32(end - j)
  1021  			}
  1022  			sa[j>>1] = code
  1023  			end = j + 1
  1024  		}
  1025  	}
  1026  }
  1027  
  1028  func length_64(text []int64, sa []int64, numLMS int) {
  1029  	end := 0 // index of current LMS-substring end (0 indicates final LMS-substring)
  1030  
  1031  	// The encoding of N text int64s into a “length” word
  1032  	// adds 1 to each int64, packs them into the bottom
  1033  	// N*8 bits of a word, and then bitwise inverts the result.
  1034  	// That is, the text sequence A B C (hex 41 42 43)
  1035  	// encodes as ^uint64(0x42_43_44).
  1036  	// LMS-substrings can never start or end with 0xFF.
  1037  	// Adding 1 ensures the encoded int64 sequence never
  1038  	// starts or ends with 0x00, so that present int64s can be
  1039  	// distinguished from zero-padding in the top bits,
  1040  	// so the length need not be separately encoded.
  1041  	// Inverting the int64s increases the chance that a
  1042  	// 4-int64 encoding will still be ≥ len(text).
  1043  	// In particular, if the first int64 is ASCII (<= 0x7E, so +1 <= 0x7F)
  1044  	// then the high bit of the inversion will be set,
  1045  	// making it clearly not a valid length (it would be a negative one).
  1046  	//
  1047  	// cx holds the pre-inverted encoding (the packed incremented int64s).
  1048  
  1049  	// This stanza (until the blank line) is the "LMS-substring iterator",
  1050  	// described in placeLMS_64 above, with one line added to maintain cx.
  1051  	c0, c1, isTypeS := int64(0), int64(0), false
  1052  	for i := len(text) - 1; i >= 0; i-- {
  1053  		c0, c1 = text[i], c0
  1054  		if c0 < c1 {
  1055  			isTypeS = true
  1056  		} else if c0 > c1 && isTypeS {
  1057  			isTypeS = false
  1058  
  1059  			// Index j = i+1 is the start of an LMS-substring.
  1060  			// Compute length or encoded text to store in sa[j/2].
  1061  			j := i + 1
  1062  			var code int64
  1063  			if end == 0 {
  1064  				code = 0
  1065  			} else {
  1066  				code = int64(end - j)
  1067  			}
  1068  			sa[j>>1] = code
  1069  			end = j + 1
  1070  		}
  1071  	}
  1072  }
  1073  
  1074  func assignID_8_64(text []byte, sa []int64, numLMS int) int {
  1075  	id := 0
  1076  	lastLen := int64(-1) // impossible
  1077  	lastPos := int64(0)
  1078  	for _, j := range sa[len(sa)-numLMS:] {
  1079  		// Is the LMS-substring at index j new, or is it the same as the last one we saw?
  1080  		n := sa[j/2]
  1081  		if n != lastLen {
  1082  			goto New
  1083  		}
  1084  		if uint64(n) >= uint64(len(text)) {
  1085  			// “Length” is really encoded full text, and they match.
  1086  			goto Same
  1087  		}
  1088  		{
  1089  			// Compare actual texts.
  1090  			n := int(n)
  1091  			this := text[j:][:n]
  1092  			last := text[lastPos:][:n]
  1093  			for i := 0; i < n; i++ {
  1094  				if this[i] != last[i] {
  1095  					goto New
  1096  				}
  1097  			}
  1098  			goto Same
  1099  		}
  1100  	New:
  1101  		id++
  1102  		lastPos = j
  1103  		lastLen = n
  1104  	Same:
  1105  		sa[j/2] = int64(id)
  1106  	}
  1107  	return id
  1108  }
  1109  
  1110  func assignID_32(text []int32, sa []int32, numLMS int) int {
  1111  	id := 0
  1112  	lastLen := int32(-1) // impossible
  1113  	lastPos := int32(0)
  1114  	for _, j := range sa[len(sa)-numLMS:] {
  1115  		// Is the LMS-substring at index j new, or is it the same as the last one we saw?
  1116  		n := sa[j/2]
  1117  		if n != lastLen {
  1118  			goto New
  1119  		}
  1120  		if uint32(n) >= uint32(len(text)) {
  1121  			// “Length” is really encoded full text, and they match.
  1122  			goto Same
  1123  		}
  1124  		{
  1125  			// Compare actual texts.
  1126  			n := int(n)
  1127  			this := text[j:][:n]
  1128  			last := text[lastPos:][:n]
  1129  			for i := 0; i < n; i++ {
  1130  				if this[i] != last[i] {
  1131  					goto New
  1132  				}
  1133  			}
  1134  			goto Same
  1135  		}
  1136  	New:
  1137  		id++
  1138  		lastPos = j
  1139  		lastLen = n
  1140  	Same:
  1141  		sa[j/2] = int32(id)
  1142  	}
  1143  	return id
  1144  }
  1145  
  1146  func assignID_64(text []int64, sa []int64, numLMS int) int {
  1147  	id := 0
  1148  	lastLen := int64(-1) // impossible
  1149  	lastPos := int64(0)
  1150  	for _, j := range sa[len(sa)-numLMS:] {
  1151  		// Is the LMS-substring at index j new, or is it the same as the last one we saw?
  1152  		n := sa[j/2]
  1153  		if n != lastLen {
  1154  			goto New
  1155  		}
  1156  		if uint64(n) >= uint64(len(text)) {
  1157  			// “Length” is really encoded full text, and they match.
  1158  			goto Same
  1159  		}
  1160  		{
  1161  			// Compare actual texts.
  1162  			n := int(n)
  1163  			this := text[j:][:n]
  1164  			last := text[lastPos:][:n]
  1165  			for i := 0; i < n; i++ {
  1166  				if this[i] != last[i] {
  1167  					goto New
  1168  				}
  1169  			}
  1170  			goto Same
  1171  		}
  1172  	New:
  1173  		id++
  1174  		lastPos = j
  1175  		lastLen = n
  1176  	Same:
  1177  		sa[j/2] = int64(id)
  1178  	}
  1179  	return id
  1180  }
  1181  
  1182  func map_64(sa []int64, numLMS int) {
  1183  	w := len(sa)
  1184  	for i := len(sa) / 2; i >= 0; i-- {
  1185  		j := sa[i]
  1186  		if j > 0 {
  1187  			w--
  1188  			sa[w] = j - 1
  1189  		}
  1190  	}
  1191  }
  1192  
  1193  func recurse_64(sa, oldTmp []int64, numLMS, maxID int) {
  1194  	dst, saTmp, text := sa[:numLMS], sa[numLMS:len(sa)-numLMS], sa[len(sa)-numLMS:]
  1195  
  1196  	// Set up temporary space for recursive call.
  1197  	// We must pass sais_64 a tmp buffer wiith at least maxID entries.
  1198  	//
  1199  	// The subproblem is guaranteed to have length at most len(sa)/2,
  1200  	// so that sa can hold both the subproblem and its suffix array.
  1201  	// Nearly all the time, however, the subproblem has length < len(sa)/3,
  1202  	// in which case there is a subproblem-sized middle of sa that
  1203  	// we can reuse for temporary space (saTmp).
  1204  	// When recurse_64 is called from sais_8_64, oldTmp is length 512
  1205  	// (from text_64), and saTmp will typically be much larger, so we'll use saTmp.
  1206  	// When deeper recursions come back to recurse_64, now oldTmp is
  1207  	// the saTmp from the top-most recursion, it is typically larger than
  1208  	// the current saTmp (because the current sa gets smaller and smaller
  1209  	// as the recursion gets deeper), and we keep reusing that top-most
  1210  	// large saTmp instead of the offered smaller ones.
  1211  	//
  1212  	// Why is the subproblem length so often just under len(sa)/3?
  1213  	// See Nong, Zhang, and Chen, section 3.6 for a plausible explanation.
  1214  	// In brief, the len(sa)/2 case would correspond to an SLSLSLSLSLSL pattern
  1215  	// in the input, perfect alternation of larger and smaller input bytes.
  1216  	// Real text doesn't do that. If each L-type index is randomly followed
  1217  	// by either an L-type or S-type index, then half the substrings will
  1218  	// be of the form SLS, but the other half will be longer. Of that half,
  1219  	// half (a quarter overall) will be SLLS; an eighth will be SLLLS, and so on.
  1220  	// Not counting the final S in each (which overlaps the first S in the next),
  1221  	// This works out to an average length 2×½ + 3×¼ + 4×⅛ + ... = 3.
  1222  	// The space we need is further reduced by the fact that many of the
  1223  	// short patterns like SLS will often be the same character sequences
  1224  	// repeated throughout the text, reducing maxID relative to numLMS.
  1225  	//
  1226  	// For short inputs, the averages may not run in our favor, but then we
  1227  	// can often fall back to using the length-512 tmp available in the
  1228  	// top-most call. (Also a short allocation would not be a big deal.)
  1229  	//
  1230  	// For pathological inputs, we fall back to allocating a new tmp of length
  1231  	// max(maxID, numLMS/2). This level of the recursion needs maxID,
  1232  	// and all deeper levels of the recursion will need no more than numLMS/2,
  1233  	// so this one allocation is guaranteed to suffice for the entire stack
  1234  	// of recursive calls.
  1235  	tmp := oldTmp
  1236  	if len(tmp) < len(saTmp) {
  1237  		tmp = saTmp
  1238  	}
  1239  	if len(tmp) < numLMS {
  1240  		// TestSAIS/forcealloc reaches this code.
  1241  		n := maxID
  1242  		if n < numLMS/2 {
  1243  			n = numLMS / 2
  1244  		}
  1245  		tmp = make([]int64, n)
  1246  	}
  1247  
  1248  	// sais_64 requires that the caller arrange to clear dst,
  1249  	// because in general the caller may know dst is
  1250  	// freshly-allocated and already cleared. But this one is not.
  1251  	for i := range dst {
  1252  		dst[i] = 0
  1253  	}
  1254  	sais_64(text, maxID, dst, tmp)
  1255  }
  1256  
  1257  func unmap_8_64(text []byte, sa []int64, numLMS int) {
  1258  	unmap := sa[len(sa)-numLMS:]
  1259  	j := len(unmap)
  1260  
  1261  	// "LMS-substring iterator" (see placeLMS_8_64 above).
  1262  	c0, c1, isTypeS := byte(0), byte(0), false
  1263  	for i := len(text) - 1; i >= 0; i-- {
  1264  		c0, c1 = text[i], c0
  1265  		if c0 < c1 {
  1266  			isTypeS = true
  1267  		} else if c0 > c1 && isTypeS {
  1268  			isTypeS = false
  1269  
  1270  			// Populate inverse map.
  1271  			j--
  1272  			unmap[j] = int64(i + 1)
  1273  		}
  1274  	}
  1275  
  1276  	// Apply inverse map to subproblem suffix array.
  1277  	sa = sa[:numLMS]
  1278  	for i := 0; i < len(sa); i++ {
  1279  		sa[i] = unmap[sa[i]]
  1280  	}
  1281  }
  1282  
  1283  func unmap_32(text []int32, sa []int32, numLMS int) {
  1284  	unmap := sa[len(sa)-numLMS:]
  1285  	j := len(unmap)
  1286  
  1287  	// "LMS-substring iterator" (see placeLMS_32 above).
  1288  	c0, c1, isTypeS := int32(0), int32(0), false
  1289  	for i := len(text) - 1; i >= 0; i-- {
  1290  		c0, c1 = text[i], c0
  1291  		if c0 < c1 {
  1292  			isTypeS = true
  1293  		} else if c0 > c1 && isTypeS {
  1294  			isTypeS = false
  1295  
  1296  			// Populate inverse map.
  1297  			j--
  1298  			unmap[j] = int32(i + 1)
  1299  		}
  1300  	}
  1301  
  1302  	// Apply inverse map to subproblem suffix array.
  1303  	sa = sa[:numLMS]
  1304  	for i := 0; i < len(sa); i++ {
  1305  		sa[i] = unmap[sa[i]]
  1306  	}
  1307  }
  1308  
  1309  func unmap_64(text []int64, sa []int64, numLMS int) {
  1310  	unmap := sa[len(sa)-numLMS:]
  1311  	j := len(unmap)
  1312  
  1313  	// "LMS-substring iterator" (see placeLMS_64 above).
  1314  	c0, c1, isTypeS := int64(0), int64(0), false
  1315  	for i := len(text) - 1; i >= 0; i-- {
  1316  		c0, c1 = text[i], c0
  1317  		if c0 < c1 {
  1318  			isTypeS = true
  1319  		} else if c0 > c1 && isTypeS {
  1320  			isTypeS = false
  1321  
  1322  			// Populate inverse map.
  1323  			j--
  1324  			unmap[j] = int64(i + 1)
  1325  		}
  1326  	}
  1327  
  1328  	// Apply inverse map to subproblem suffix array.
  1329  	sa = sa[:numLMS]
  1330  	for i := 0; i < len(sa); i++ {
  1331  		sa[i] = unmap[sa[i]]
  1332  	}
  1333  }
  1334  
  1335  func expand_8_64(text []byte, freq, bucket, sa []int64, numLMS int) {
  1336  	bucketMax_8_64(text, freq, bucket)
  1337  	bucket = bucket[:256] // eliminate bound check for bucket[c] below
  1338  
  1339  	// Loop backward through sa, always tracking
  1340  	// the next index to populate from sa[:numLMS].
  1341  	// When we get to one, populate it.
  1342  	// Zero the rest of the slots; they have dead values in them.
  1343  	x := numLMS - 1
  1344  	saX := sa[x]
  1345  	c := text[saX]
  1346  	b := bucket[c] - 1
  1347  	bucket[c] = b
  1348  
  1349  	for i := len(sa) - 1; i >= 0; i-- {
  1350  		if i != int(b) {
  1351  			sa[i] = 0
  1352  			continue
  1353  		}
  1354  		sa[i] = saX
  1355  
  1356  		// Load next entry to put down (if any).
  1357  		if x > 0 {
  1358  			x--
  1359  			saX = sa[x] // TODO bounds check
  1360  			c = text[saX]
  1361  			b = bucket[c] - 1
  1362  			bucket[c] = b
  1363  		}
  1364  	}
  1365  }
  1366  
  1367  func expand_32(text []int32, freq, bucket, sa []int32, numLMS int) {
  1368  	bucketMax_32(text, freq, bucket)
  1369  
  1370  	// Loop backward through sa, always tracking
  1371  	// the next index to populate from sa[:numLMS].
  1372  	// When we get to one, populate it.
  1373  	// Zero the rest of the slots; they have dead values in them.
  1374  	x := numLMS - 1
  1375  	saX := sa[x]
  1376  	c := text[saX]
  1377  	b := bucket[c] - 1
  1378  	bucket[c] = b
  1379  
  1380  	for i := len(sa) - 1; i >= 0; i-- {
  1381  		if i != int(b) {
  1382  			sa[i] = 0
  1383  			continue
  1384  		}
  1385  		sa[i] = saX
  1386  
  1387  		// Load next entry to put down (if any).
  1388  		if x > 0 {
  1389  			x--
  1390  			saX = sa[x] // TODO bounds check
  1391  			c = text[saX]
  1392  			b = bucket[c] - 1
  1393  			bucket[c] = b
  1394  		}
  1395  	}
  1396  }
  1397  
  1398  func expand_64(text []int64, freq, bucket, sa []int64, numLMS int) {
  1399  	bucketMax_64(text, freq, bucket)
  1400  
  1401  	// Loop backward through sa, always tracking
  1402  	// the next index to populate from sa[:numLMS].
  1403  	// When we get to one, populate it.
  1404  	// Zero the rest of the slots; they have dead values in them.
  1405  	x := numLMS - 1
  1406  	saX := sa[x]
  1407  	c := text[saX]
  1408  	b := bucket[c] - 1
  1409  	bucket[c] = b
  1410  
  1411  	for i := len(sa) - 1; i >= 0; i-- {
  1412  		if i != int(b) {
  1413  			sa[i] = 0
  1414  			continue
  1415  		}
  1416  		sa[i] = saX
  1417  
  1418  		// Load next entry to put down (if any).
  1419  		if x > 0 {
  1420  			x--
  1421  			saX = sa[x] // TODO bounds check
  1422  			c = text[saX]
  1423  			b = bucket[c] - 1
  1424  			bucket[c] = b
  1425  		}
  1426  	}
  1427  }
  1428  
  1429  func induceL_8_64(text []byte, sa, freq, bucket []int64) {
  1430  	// Initialize positions for left side of character buckets.
  1431  	bucketMin_8_64(text, freq, bucket)
  1432  	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below
  1433  
  1434  	// This scan is similar to the one in induceSubL_8_64 above.
  1435  	// That one arranges to clear all but the leftmost L-type indexes.
  1436  	// This scan leaves all the L-type indexes and the original S-type
  1437  	// indexes, but it negates the positive leftmost L-type indexes
  1438  	// (the ones that induceS_8_64 needs to process).
  1439  
  1440  	// expand_8_64 left out the implicit entry sa[-1] == len(text),
  1441  	// corresponding to the identified type-L index len(text)-1.
  1442  	// Process it before the left-to-right scan of sa proper.
  1443  	// See body in loop for commentary.
  1444  	k := len(text) - 1
  1445  	c0, c1 := text[k-1], text[k]
  1446  	if c0 < c1 {
  1447  		k = -k
  1448  	}
  1449  
  1450  	// Cache recently used bucket index.
  1451  	cB := c1
  1452  	b := bucket[cB]
  1453  	sa[b] = int64(k)
  1454  	b++
  1455  
  1456  	for i := 0; i < len(sa); i++ {
  1457  		j := int(sa[i])
  1458  		if j <= 0 {
  1459  			// Skip empty or negated entry (including negated zero).
  1460  			continue
  1461  		}
  1462  
  1463  		// Index j was on work queue, meaning k := j-1 is L-type,
  1464  		// so we can now place k correctly into sa.
  1465  		// If k-1 is L-type, queue k for processing later in this loop.
  1466  		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
  1467  		// If k is zero, k-1 doesn't exist, so we only need to leave it
  1468  		// for the caller. The caller can't tell the difference between
  1469  		// an empty slot and a non-empty zero, but there's no need
  1470  		// to distinguish them anyway: the final suffix array will end up
  1471  		// with one zero somewhere, and that will be a real zero.
  1472  		k := j - 1
  1473  		c1 := text[k]
  1474  		if k > 0 {
  1475  			if c0 := text[k-1]; c0 < c1 {
  1476  				k = -k
  1477  			}
  1478  		}
  1479  
  1480  		if cB != c1 {
  1481  			bucket[cB] = b
  1482  			cB = c1
  1483  			b = bucket[cB]
  1484  		}
  1485  		sa[b] = int64(k)
  1486  		b++
  1487  	}
  1488  }
  1489  
  1490  func induceL_32(text []int32, sa, freq, bucket []int32) {
  1491  	// Initialize positions for left side of character buckets.
  1492  	bucketMin_32(text, freq, bucket)
  1493  
  1494  	// This scan is similar to the one in induceSubL_32 above.
  1495  	// That one arranges to clear all but the leftmost L-type indexes.
  1496  	// This scan leaves all the L-type indexes and the original S-type
  1497  	// indexes, but it negates the positive leftmost L-type indexes
  1498  	// (the ones that induceS_32 needs to process).
  1499  
  1500  	// expand_32 left out the implicit entry sa[-1] == len(text),
  1501  	// corresponding to the identified type-L index len(text)-1.
  1502  	// Process it before the left-to-right scan of sa proper.
  1503  	// See body in loop for commentary.
  1504  	k := len(text) - 1
  1505  	c0, c1 := text[k-1], text[k]
  1506  	if c0 < c1 {
  1507  		k = -k
  1508  	}
  1509  
  1510  	// Cache recently used bucket index.
  1511  	cB := c1
  1512  	b := bucket[cB]
  1513  	sa[b] = int32(k)
  1514  	b++
  1515  
  1516  	for i := 0; i < len(sa); i++ {
  1517  		j := int(sa[i])
  1518  		if j <= 0 {
  1519  			// Skip empty or negated entry (including negated zero).
  1520  			continue
  1521  		}
  1522  
  1523  		// Index j was on work queue, meaning k := j-1 is L-type,
  1524  		// so we can now place k correctly into sa.
  1525  		// If k-1 is L-type, queue k for processing later in this loop.
  1526  		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
  1527  		// If k is zero, k-1 doesn't exist, so we only need to leave it
  1528  		// for the caller. The caller can't tell the difference between
  1529  		// an empty slot and a non-empty zero, but there's no need
  1530  		// to distinguish them anyway: the final suffix array will end up
  1531  		// with one zero somewhere, and that will be a real zero.
  1532  		k := j - 1
  1533  		c1 := text[k]
  1534  		if k > 0 {
  1535  			if c0 := text[k-1]; c0 < c1 {
  1536  				k = -k
  1537  			}
  1538  		}
  1539  
  1540  		if cB != c1 {
  1541  			bucket[cB] = b
  1542  			cB = c1
  1543  			b = bucket[cB]
  1544  		}
  1545  		sa[b] = int32(k)
  1546  		b++
  1547  	}
  1548  }
  1549  
  1550  func induceL_64(text []int64, sa, freq, bucket []int64) {
  1551  	// Initialize positions for left side of character buckets.
  1552  	bucketMin_64(text, freq, bucket)
  1553  
  1554  	// This scan is similar to the one in induceSubL_64 above.
  1555  	// That one arranges to clear all but the leftmost L-type indexes.
  1556  	// This scan leaves all the L-type indexes and the original S-type
  1557  	// indexes, but it negates the positive leftmost L-type indexes
  1558  	// (the ones that induceS_64 needs to process).
  1559  
  1560  	// expand_64 left out the implicit entry sa[-1] == len(text),
  1561  	// corresponding to the identified type-L index len(text)-1.
  1562  	// Process it before the left-to-right scan of sa proper.
  1563  	// See body in loop for commentary.
  1564  	k := len(text) - 1
  1565  	c0, c1 := text[k-1], text[k]
  1566  	if c0 < c1 {
  1567  		k = -k
  1568  	}
  1569  
  1570  	// Cache recently used bucket index.
  1571  	cB := c1
  1572  	b := bucket[cB]
  1573  	sa[b] = int64(k)
  1574  	b++
  1575  
  1576  	for i := 0; i < len(sa); i++ {
  1577  		j := int(sa[i])
  1578  		if j <= 0 {
  1579  			// Skip empty or negated entry (including negated zero).
  1580  			continue
  1581  		}
  1582  
  1583  		// Index j was on work queue, meaning k := j-1 is L-type,
  1584  		// so we can now place k correctly into sa.
  1585  		// If k-1 is L-type, queue k for processing later in this loop.
  1586  		// If k-1 is S-type (text[k-1] < text[k]), queue -k to save for the caller.
  1587  		// If k is zero, k-1 doesn't exist, so we only need to leave it
  1588  		// for the caller. The caller can't tell the difference between
  1589  		// an empty slot and a non-empty zero, but there's no need
  1590  		// to distinguish them anyway: the final suffix array will end up
  1591  		// with one zero somewhere, and that will be a real zero.
  1592  		k := j - 1
  1593  		c1 := text[k]
  1594  		if k > 0 {
  1595  			if c0 := text[k-1]; c0 < c1 {
  1596  				k = -k
  1597  			}
  1598  		}
  1599  
  1600  		if cB != c1 {
  1601  			bucket[cB] = b
  1602  			cB = c1
  1603  			b = bucket[cB]
  1604  		}
  1605  		sa[b] = int64(k)
  1606  		b++
  1607  	}
  1608  }
  1609  
  1610  func induceS_8_64(text []byte, sa, freq, bucket []int64) {
  1611  	// Initialize positions for right side of character buckets.
  1612  	bucketMax_8_64(text, freq, bucket)
  1613  	bucket = bucket[:256] // eliminate bounds check for bucket[cB] below
  1614  
  1615  	cB := byte(0)
  1616  	b := bucket[cB]
  1617  
  1618  	for i := len(sa) - 1; i >= 0; i-- {
  1619  		j := int(sa[i])
  1620  		if j >= 0 {
  1621  			// Skip non-flagged entry.
  1622  			// (This loop can't see an empty entry; 0 means the real zero index.)
  1623  			continue
  1624  		}
  1625  
  1626  		// Negative j is a work queue entry; rewrite to positive j for final suffix array.
  1627  		j = -j
  1628  		sa[i] = int64(j)
  1629  
  1630  		// Index j was on work queue (encoded as -j but now decoded),
  1631  		// meaning k := j-1 is L-type,
  1632  		// so we can now place k correctly into sa.
  1633  		// If k-1 is S-type, queue -k for processing later in this loop.
  1634  		// If k-1 is L-type (text[k-1] > text[k]), queue k to save for the caller.
  1635  		// If k is zero, k-1 doesn't exist, so we only need to leave it
  1636  		// for the caller.
  1637  		k := j - 1
  1638  		c1 := text[k]
  1639  		if k > 0 {
  1640  			if c0 := text[k-1]; c0 <= c1 {
  1641  				k = -k
  1642  			}
  1643  		}
  1644  
  1645  		if cB != c1 {
  1646  			bucket[cB] = b
  1647  			cB = c1
  1648  			b = bucket[cB]
  1649  		}
  1650  		b--
  1651  		sa[b] = int64(k)
  1652  	}
  1653  }
  1654  
  1655  func induceS_32(text []int32, sa, freq, bucket []int32) {
  1656  	// Initialize positions for right side of character buckets.
  1657  	bucketMax_32(text, freq, bucket)
  1658  
  1659  	cB := int32(0)
  1660  	b := bucket[cB]
  1661  
  1662  	for i := len(sa) - 1; i >= 0; i-- {
  1663  		j := int(sa[i])
  1664  		if j >= 0 {
  1665  			// Skip non-flagged entry.
  1666  			// (This loop can't see an empty entry; 0 means the real zero index.)
  1667  			continue
  1668  		}
  1669  
  1670  		// Negative j is a work queue entry; rewrite to positive j for final suffix array.
  1671  		j = -j
  1672  		sa[i] = int32(j)
  1673  
  1674  		// Index j was on work queue (encoded as -j but now decoded),
  1675  		// meaning k := j-1 is L-type,
  1676  		// so we can now place k correctly into sa.
  1677  		// If k-1 is S-type, queue -k for processing later in this loop.
  1678  		// If k-1 is L-type (text[k-1] > text[k]), queue k to save for the caller.
  1679  		// If k is zero, k-1 doesn't exist, so we only need to leave it
  1680  		// for the caller.
  1681  		k := j - 1
  1682  		c1 := text[k]
  1683  		if k > 0 {
  1684  			if c0 := text[k-1]; c0 <= c1 {
  1685  				k = -k
  1686  			}
  1687  		}
  1688  
  1689  		if cB != c1 {
  1690  			bucket[cB] = b
  1691  			cB = c1
  1692  			b = bucket[cB]
  1693  		}
  1694  		b--
  1695  		sa[b] = int32(k)
  1696  	}
  1697  }
  1698  
  1699  func induceS_64(text []int64, sa, freq, bucket []int64) {
  1700  	// Initialize positions for right side of character buckets.
  1701  	bucketMax_64(text, freq, bucket)
  1702  
  1703  	cB := int64(0)
  1704  	b := bucket[cB]
  1705  
  1706  	for i := len(sa) - 1; i >= 0; i-- {
  1707  		j := int(sa[i])
  1708  		if j >= 0 {
  1709  			// Skip non-flagged entry.
  1710  			// (This loop can't see an empty entry; 0 means the real zero index.)
  1711  			continue
  1712  		}
  1713  
  1714  		// Negative j is a work queue entry; rewrite to positive j for final suffix array.
  1715  		j = -j
  1716  		sa[i] = int64(j)
  1717  
  1718  		// Index j was on work queue (encoded as -j but now decoded),
  1719  		// meaning k := j-1 is L-type,
  1720  		// so we can now place k correctly into sa.
  1721  		// If k-1 is S-type, queue -k for processing later in this loop.
  1722  		// If k-1 is L-type (text[k-1] > text[k]), queue k to save for the caller.
  1723  		// If k is zero, k-1 doesn't exist, so we only need to leave it
  1724  		// for the caller.
  1725  		k := j - 1
  1726  		c1 := text[k]
  1727  		if k > 0 {
  1728  			if c0 := text[k-1]; c0 <= c1 {
  1729  				k = -k
  1730  			}
  1731  		}
  1732  
  1733  		if cB != c1 {
  1734  			bucket[cB] = b
  1735  			cB = c1
  1736  			b = bucket[cB]
  1737  		}
  1738  		b--
  1739  		sa[b] = int64(k)
  1740  	}
  1741  }
  1742  

View as plain text