github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/astrobwt/sais2.go (about) 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 astrobwt 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 }