koffi 2.12.3 → 2.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,6 +20,7 @@
20
20
  // OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  #include "base.hh"
23
+ #include "crc.inc"
23
24
  #include "unicode.inc"
24
25
 
25
26
  #if __has_include("vendor/dragonbox/include/dragonbox/dragonbox.h")
@@ -1855,6 +1856,35 @@ void FmtLowerAscii::Format(FunctionRef<void(Span<const char>)> append) const
1855
1856
  }
1856
1857
  }
1857
1858
 
1859
+ void FmtEscape::Format(FunctionRef<void(Span<const char>)> append) const
1860
+ {
1861
+ static const char literals[] = "0123456789ABCDEF";
1862
+
1863
+ for (char c: str) {
1864
+ if (c >= 32 && (unsigned int)c < 128) {
1865
+ append(c);
1866
+ } else {
1867
+ switch (c) {
1868
+ case '\t': { append('\t'); } break;
1869
+ case '\r': { append("\r"); } break;
1870
+ case '\n': { append("\n"); } break;
1871
+
1872
+ default: {
1873
+ char encoded[4];
1874
+
1875
+ encoded[0] = '\\';
1876
+ encoded[1] = 'x';
1877
+ encoded[2] = literals[((uint8_t)c >> 4) & 0xF];
1878
+ encoded[3] = literals[((uint8_t)c >> 0) & 0xF];
1879
+
1880
+ Span<const char> buf = MakeSpan(encoded, 4);
1881
+ append(buf);
1882
+ } break;
1883
+ }
1884
+ }
1885
+ }
1886
+ }
1887
+
1858
1888
  void FmtUrlSafe::Format(FunctionRef<void(Span<const char>)> append) const
1859
1889
  {
1860
1890
  static const char literals[] = "0123456789ABCDEF";
@@ -4474,14 +4504,44 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4474
4504
  int64_t max = size;
4475
4505
  progress(0, max);
4476
4506
 
4477
- #if defined(__linux__) || defined(__FreeBSD__)
4478
4507
  // Try copy_file_range() if available
4508
+ #if defined(SYS_copy_file_range)
4509
+ {
4510
+ bool first = true;
4511
+
4512
+ while (size) {
4513
+ // glibc < 2.27 doesn't define copy_file_range
4514
+
4515
+ size_t count = (size_t)std::min(size, (int64_t)Mebibytes(64));
4516
+ ssize_t ret = syscall(SYS_copy_file_range, src_fd, (off_t *)&src_offset, dest_fd, (off_t *)&dest_offset, count, 0u);
4517
+
4518
+ if (ret < 0) {
4519
+ if (first && errno == EXDEV)
4520
+ goto xdev;
4521
+ if (errno == EINTR)
4522
+ continue;
4523
+
4524
+ LogError("Failed to copy '%1' to '%2': %3", src_filename, dest_filename, strerror(errno));
4525
+ return false;
4526
+ }
4527
+
4528
+ first = false;
4529
+ size -= ret;
4530
+
4531
+ progress(max - size, max);
4532
+ }
4533
+
4534
+ return true;
4535
+ }
4536
+
4537
+ xdev:
4538
+ #elif defined(__FreeBSD__)
4479
4539
  {
4480
4540
  bool first = true;
4481
4541
 
4482
4542
  while (size) {
4483
4543
  size_t count = (size_t)std::min(size, (int64_t)Mebibytes(64));
4484
- ssize_t ret = copy_file_range(src_fd, (off_t *)&src_offset, dest_fd, (off_t *)&dest_offset, count, 0);
4544
+ ssize_t ret = copy_file_range(src_fd, (off_t *)&src_offset, dest_fd, (off_t *)&dest_offset, count, 0u);
4485
4545
 
4486
4546
  if (ret < 0) {
4487
4547
  if (first && errno == EXDEV)
@@ -5964,16 +6024,12 @@ const char *GetTemporaryDirectory()
5964
6024
 
5965
6025
  #endif
5966
6026
 
5967
- const char *FindConfigFile(Span<const char *const> names, Allocator *alloc,
5968
- HeapArray<const char *> *out_possibilities)
6027
+ const char *FindConfigFile(const char *directory, Span<const char *const> names,
6028
+ Allocator *alloc, HeapArray<const char *> *out_possibilities)
5969
6029
  {
5970
- decltype(GetUserConfigPath) *funcs[] = {
5971
- [](const char *name, Allocator *alloc) {
5972
- Span<const char> dir = GetApplicationDirectory();
6030
+ RG_ASSERT(!directory || directory[0]);
5973
6031
 
5974
- const char *filename = Fmt(alloc, "%1%/%2", dir, name).ptr;
5975
- return filename;
5976
- },
6032
+ decltype(GetUserConfigPath) *funcs[] = {
5977
6033
  GetUserConfigPath,
5978
6034
  #if !defined(_WIN32)
5979
6035
  GetSystemConfigPath
@@ -5982,19 +6038,46 @@ const char *FindConfigFile(Span<const char *const> names, Allocator *alloc,
5982
6038
 
5983
6039
  const char *filename = nullptr;
5984
6040
 
5985
- for (const auto &func: funcs) {
6041
+ // Try application directory
6042
+ for (const char *name: names) {
6043
+ Span<const char> dir = GetApplicationDirectory();
6044
+ const char *path = Fmt(alloc, "%1%/%2", dir, name).ptr;
6045
+
6046
+ if (!filename && TestFile(path, FileType::File)) {
6047
+ filename = path;
6048
+ }
6049
+ if (out_possibilities) {
6050
+ out_possibilities->Append(path);
6051
+ }
6052
+ }
6053
+
6054
+ LocalArray<const char *, 8> tests;
6055
+ {
6056
+ RG_ASSERT(names.len <= tests.Available());
6057
+
5986
6058
  for (const char *name: names) {
5987
- const char *path = func(name, alloc);
6059
+ if (directory) {
6060
+ const char *test = Fmt(alloc, "%1%/%2", directory, name).ptr;
6061
+ tests.Append(test);
6062
+ } else {
6063
+ tests.Append(name);
6064
+ }
6065
+ }
6066
+ }
6067
+
6068
+ // Try standard paths
6069
+ for (const auto &func: funcs) {
6070
+ for (const char *test: tests) {
6071
+ const char *path = func(test, alloc);
5988
6072
 
5989
6073
  if (!path)
5990
6074
  continue;
5991
6075
 
5992
- if (TestFile(path, FileType::File)) {
6076
+ if (!filename && TestFile(path, FileType::File)) {
5993
6077
  filename = path;
5994
6078
  }
5995
6079
  if (out_possibilities) {
5996
6080
  out_possibilities->Append(path);
5997
- break;
5998
6081
  }
5999
6082
  }
6000
6083
  }
@@ -9083,8 +9166,10 @@ bool ConsolePrompter::Read(Span<const char> *out_str)
9083
9166
  }
9084
9167
  }
9085
9168
 
9086
- bool ConsolePrompter::ReadYN(bool *out_value)
9169
+ Size ConsolePrompter::ReadEnum(Span<const PromptChoice> choices, Size value)
9087
9170
  {
9171
+ RG_ASSERT(value < choices.len);
9172
+
9088
9173
  #if !defined(_WIN32) && !defined(__wasm__)
9089
9174
  struct sigaction old_sa;
9090
9175
  IgnoreSigWinch(&old_sa);
@@ -9097,9 +9182,9 @@ bool ConsolePrompter::ReadYN(bool *out_value)
9097
9182
  DisableRawMode();
9098
9183
  };
9099
9184
 
9100
- return ReadRawYN(out_value);
9185
+ return ReadRawEnum(choices, value);
9101
9186
  } else {
9102
- return ReadBufferedYN(out_value);
9187
+ return ReadBufferedEnum(choices);
9103
9188
  }
9104
9189
  }
9105
9190
 
@@ -9126,8 +9211,8 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
9126
9211
  StdErr->Flush();
9127
9212
 
9128
9213
  prompt_columns = ComputeWidth(prompt);
9129
-
9130
9214
  str_offset = str.len;
9215
+
9131
9216
  RenderRaw();
9132
9217
 
9133
9218
  int32_t uc;
@@ -9350,18 +9435,13 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
9350
9435
  return true;
9351
9436
  }
9352
9437
 
9353
- bool ConsolePrompter::ReadRawYN(bool *out_value)
9438
+ Size ConsolePrompter::ReadRawEnum(Span<const PromptChoice> choices, Size value)
9354
9439
  {
9355
- const char *yn = "[Y/N]";
9356
-
9357
9440
  StdErr->Flush();
9358
9441
 
9359
- prompt_columns = ComputeWidth(prompt) + ComputeWidth(yn) + 1;
9360
-
9361
- str.RemoveFrom(0);
9362
- str_offset = 0;
9442
+ prompt_columns = 0;
9443
+ FormatChoices(choices, value);
9363
9444
  RenderRaw();
9364
- Print(StdErr, "%!D..%1%!0 ", yn);
9365
9445
 
9366
9446
  int32_t uc;
9367
9447
  while ((uc = ReadChar()) >= 0) {
@@ -9372,36 +9452,86 @@ bool ConsolePrompter::ReadRawYN(bool *out_value)
9372
9452
  }
9373
9453
 
9374
9454
  switch (uc) {
9375
- case 0x3: { // Ctrl-C
9376
- StdErr->Write("\r\n");
9377
- StdErr->Flush();
9455
+ case 0x1B: {
9456
+ LocalArray<char, 16> buf;
9378
9457
 
9379
- return false;
9380
- } break;
9381
- case 0x4: { // Ctrl-D
9382
- return false;
9458
+ const auto match_escape = [&](const char *seq) {
9459
+ RG_ASSERT(strlen(seq) < RG_SIZE(buf.data));
9460
+
9461
+ for (Size i = 0; seq[i]; i++) {
9462
+ if (i >= buf.len) {
9463
+ uc = ReadChar();
9464
+
9465
+ if (uc >= 128) {
9466
+ // Got some kind of non-ASCII character, make sure nothing else matches
9467
+ buf.Append(0);
9468
+ return false;
9469
+ }
9470
+
9471
+ buf.Append((char)uc);
9472
+ }
9473
+ if (buf[i] != seq[i])
9474
+ return false;
9475
+ }
9476
+
9477
+ return true;
9478
+ };
9479
+
9480
+ if (match_escape("[A")) { // Up
9481
+ fake_input = "\x10";
9482
+ } else if (match_escape("[B")) { // Down
9483
+ fake_input = "\x0E";
9484
+ }
9383
9485
  } break;
9384
9486
 
9385
- case 'Y':
9386
- case 'y': {
9387
- StdErr->Write("Y\n");
9487
+ case 0x3: // Ctrl-C
9488
+ case 0x4: { // Ctrl-D
9489
+ if (rows > y) {
9490
+ Print(StdErr, "\x1B[%1B", rows - y);
9491
+ }
9492
+ StdErr->Write("\r");
9388
9493
  StdErr->Flush();
9389
9494
 
9390
- *out_value = true;
9391
- return true;
9495
+ return -1;
9496
+ } break;
9497
+
9498
+ case 0xE: { // Down
9499
+ if (value + 1 < choices.len) {
9500
+ FormatChoices(choices, ++value);
9501
+ RenderRaw();
9502
+ }
9503
+ } break;
9504
+ case 0x10: { // Up
9505
+ if (value > 0) {
9506
+ FormatChoices(choices, --value);
9507
+ RenderRaw();
9508
+ }
9392
9509
  } break;
9393
- case 'N':
9394
- case 'n': {
9395
- StdErr->Write("N\n");
9510
+
9511
+ default: {
9512
+ const auto it = std::find_if(choices.begin(), choices.end(),
9513
+ [&](const PromptChoice &choice) { return choice.c == uc; });
9514
+ if (it == choices.end())
9515
+ break;
9516
+ value = it - choices.begin();
9517
+ } [[fallthrough]];
9518
+
9519
+ case '\r':
9520
+ case '\n': {
9521
+ str.RemoveFrom(0);
9522
+ str.Append(choices[value].str);
9523
+ str_offset = str.len;
9524
+ RenderRaw();
9525
+
9526
+ StdErr->Write("\r\n");
9396
9527
  StdErr->Flush();
9397
9528
 
9398
- *out_value = false;
9399
- return true;
9529
+ return value;
9400
9530
  } break;
9401
9531
  }
9402
9532
  }
9403
9533
 
9404
- return false;
9534
+ return -1;
9405
9535
  }
9406
9536
 
9407
9537
  bool ConsolePrompter::ReadBuffered(Span<const char> *out_str)
@@ -9430,41 +9560,43 @@ bool ConsolePrompter::ReadBuffered(Span<const char> *out_str)
9430
9560
  return false;
9431
9561
  }
9432
9562
 
9433
- bool ConsolePrompter::ReadBufferedYN(bool *out_value)
9563
+ Size ConsolePrompter::ReadBufferedEnum(Span<const PromptChoice> choices)
9434
9564
  {
9435
- const char *yn = "[Yes/No]";
9565
+ static const Span<const char> prefix = "Input your choice: ";
9436
9566
 
9437
- prompt_columns = ComputeWidth(prompt) + ComputeWidth(yn) + 1;
9567
+ prompt_columns = 0;
9568
+ FormatChoices(choices, 0);
9569
+ RenderBuffered();
9438
9570
 
9439
- while (!StdIn->IsEOF()) {
9440
- str.RemoveFrom(0);
9441
- str_offset = 0;
9442
- RenderBuffered();
9443
- Print(StdErr, "%1 ", yn);
9571
+ Print(StdErr, "\n%1", prefix);
9572
+ StdErr->Flush();
9444
9573
 
9445
- for (;;) {
9446
- uint8_t c = 0;
9447
- if (StdIn->Read(1, &c) < 0)
9448
- return false;
9574
+ do {
9575
+ uint8_t c = 0;
9576
+ if (StdIn->Read(1, &c) < 0)
9577
+ return -1;
9449
9578
 
9450
- if (c == '\n') {
9451
- if (TestStrI(str, "y") || TestStrI(str, "yes")) {
9452
- *out_value = true;
9453
- return true;
9454
- } else if (TestStrI(str, "n") || TestStrI(str, "no")) {
9455
- *out_value = false;
9456
- return true;
9457
- } else {
9458
- break;
9459
- }
9460
- } else if (c >= 32 || c == '\t') {
9461
- str.Append((char)c);
9579
+ if (c == '\n') {
9580
+ Span<const char> end = TrimStr(SplitStrReverse(str, '\n'));
9581
+
9582
+ if (end.len == 1) {
9583
+ const auto it = std::find_if(choices.begin(), choices.end(),
9584
+ [&](const PromptChoice &choice) { return choice.c == end[0]; });
9585
+ if (it != choices.end())
9586
+ return it - choices.ptr;
9462
9587
  }
9588
+
9589
+ str.RemoveFrom(end.ptr - str.ptr);
9590
+
9591
+ StdErr->Write(prefix);
9592
+ StdErr->Flush();
9593
+ } else if (c >= 32 || c == '\t') {
9594
+ str.Append((char)c);
9463
9595
  }
9464
- }
9596
+ } while (!StdIn->IsEOF());
9465
9597
 
9466
9598
  // EOF
9467
- return false;
9599
+ return -1;
9468
9600
  }
9469
9601
 
9470
9602
  void ConsolePrompter::ChangeEntry(Size new_idx)
@@ -9548,6 +9680,27 @@ void ConsolePrompter::Delete(Size start, Size end)
9548
9680
  }
9549
9681
  }
9550
9682
 
9683
+ void ConsolePrompter::FormatChoices(Span<const PromptChoice> choices, Size value)
9684
+ {
9685
+ int align = 0;
9686
+
9687
+ for (const PromptChoice &choice: choices) {
9688
+ align = std::max(align, (int)strlen(choice.str));
9689
+ }
9690
+
9691
+ str.RemoveFrom(0);
9692
+ str.Append('\n');
9693
+ for (Size i = 0; i < choices.len; i++) {
9694
+ const PromptChoice &choice = choices[i];
9695
+
9696
+ Fmt(&str, " [%1] %2 ", choice.c, FmtArg(choice.str).Pad(align));
9697
+ if (i == value) {
9698
+ str_offset = str.len;
9699
+ }
9700
+ str.Append('\n');
9701
+ }
9702
+ }
9703
+
9551
9704
  void ConsolePrompter::RenderRaw()
9552
9705
  {
9553
9706
  columns = GetConsoleSize().x;
@@ -9580,7 +9733,7 @@ void ConsolePrompter::RenderRaw()
9580
9733
  int width = mask ? mask_columns : ComputeWidth(str.Take(i, bytes));
9581
9734
 
9582
9735
  if (x2 + width >= columns || str[i] == '\n') {
9583
- FmtArg prefix = FmtArg(str[i] == '\n' ? '.' : ' ').Repeat(prompt_columns - 1);
9736
+ FmtArg prefix = FmtArg(' ').Repeat(prompt_columns - 1);
9584
9737
  Print(StdErr, "\x1B[0K\r\n%!D.+%1%!0 %!..+", prefix);
9585
9738
 
9586
9739
  x2 = prompt_columns;
@@ -9624,8 +9777,10 @@ void ConsolePrompter::RenderBuffered()
9624
9777
  Print(StdErr, "%1%2", prompt, line);
9625
9778
  while (remain.len) {
9626
9779
  line = SplitStr(remain, '\n', &remain);
9627
- Print(StdErr, "\n%1 %2", FmtArg('.').Repeat(prompt_columns - 1), line);
9780
+ Print(StdErr, "\n%1%2", FmtArg(' ').Repeat(prompt_columns), line);
9628
9781
  }
9782
+
9783
+ StdErr->Flush();
9629
9784
  }
9630
9785
 
9631
9786
  Vec2<int> ConsolePrompter::GetConsoleSize()
@@ -9831,12 +9986,42 @@ const char *Prompt(const char *prompt, const char *default_value, const char *ma
9831
9986
  return str;
9832
9987
  }
9833
9988
 
9834
- bool PromptYN(const char *prompt, bool *out_value)
9989
+ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value)
9835
9990
  {
9991
+ #if defined(RG_DEBUG)
9992
+ {
9993
+ HashSet<char> keys;
9994
+
9995
+ for (const PromptChoice &choice: choices) {
9996
+ keys.Set(choice.c);
9997
+ }
9998
+
9999
+ bool duplicates = (keys.table.count < choices.len);
10000
+ RG_ASSERT(!duplicates);
10001
+ }
10002
+ #endif
10003
+
9836
10004
  ConsolePrompter prompter;
9837
10005
  prompter.prompt = prompt;
9838
10006
 
9839
- return prompter.ReadYN(out_value);
10007
+ return prompter.ReadEnum(choices, value);
10008
+ }
10009
+
10010
+ Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value)
10011
+ {
10012
+ static const char literals[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
10013
+ RG_ASSERT(strings.len <= RG_LEN(literals));
10014
+
10015
+ HeapArray<PromptChoice> choices;
10016
+
10017
+ for (Size i = 0; i < strings.len; i++) {
10018
+ const char *str = strings[i];
10019
+ PromptChoice choice = { literals[i], str };
10020
+
10021
+ choices.Append(choice);
10022
+ }
10023
+
10024
+ return PromptEnum(prompt, choices, value);
9840
10025
  }
9841
10026
 
9842
10027
  // ------------------------------------------------------------------------
@@ -9972,4 +10157,140 @@ bool IsXidContinue(int32_t uc)
9972
10157
  return false;
9973
10158
  }
9974
10159
 
10160
+ // ------------------------------------------------------------------------
10161
+ // CRC
10162
+ // ------------------------------------------------------------------------
10163
+
10164
+ uint32_t CRC32(uint32_t state, Span<const uint8_t> buf)
10165
+ {
10166
+ state = ~state;
10167
+
10168
+ Size right = buf.len & (RG_SIZE_MAX - 3);
10169
+
10170
+ for (Size i = 0; i < right; i += 4) {
10171
+ state = (state >> 8) ^ Crc32Table[(state ^ buf[i + 0]) & 0xFF];
10172
+ state = (state >> 8) ^ Crc32Table[(state ^ buf[i + 1]) & 0xFF];
10173
+ state = (state >> 8) ^ Crc32Table[(state ^ buf[i + 2]) & 0xFF];
10174
+ state = (state >> 8) ^ Crc32Table[(state ^ buf[i + 3]) & 0xFF];
10175
+ }
10176
+ for (Size i = right; i < buf.len; i++) {
10177
+ state = (state >> 8) ^ Crc32Table[(state ^ buf[i]) & 0xFF];
10178
+ }
10179
+
10180
+ return ~state;
10181
+ }
10182
+
10183
+ uint32_t CRC32C(uint32_t state, Span<const uint8_t> buf)
10184
+ {
10185
+ state = ~state;
10186
+
10187
+ Size right = buf.len & (RG_SIZE_MAX - 3);
10188
+
10189
+ for (Size i = 0; i < right; i += 4) {
10190
+ state = (state >> 8) ^ Crc32CTable[(state ^ buf[i + 0]) & 0xFF];
10191
+ state = (state >> 8) ^ Crc32CTable[(state ^ buf[i + 1]) & 0xFF];
10192
+ state = (state >> 8) ^ Crc32CTable[(state ^ buf[i + 2]) & 0xFF];
10193
+ state = (state >> 8) ^ Crc32CTable[(state ^ buf[i + 3]) & 0xFF];
10194
+ }
10195
+ for (Size i = right; i < buf.len; i++) {
10196
+ state = (state >> 8) ^ Crc32CTable[(state ^ buf[i]) & 0xFF];
10197
+ }
10198
+
10199
+ return ~state;
10200
+ }
10201
+
10202
+ static uint64_t XzUpdate1(uint64_t state, uint8_t byte)
10203
+ {
10204
+ uint64_t ret = (state >> 8) ^ Crc64XzTable0[byte ^ (uint8_t)state];
10205
+ return ret;
10206
+ }
10207
+
10208
+ static uint64_t XzUpdate16(uint64_t state, const uint8_t *bytes)
10209
+ {
10210
+ uint64_t ret = Crc64XzTable0[bytes[15]] ^
10211
+ Crc64XzTable1[bytes[14]] ^
10212
+ Crc64XzTable2[bytes[13]] ^
10213
+ Crc64XzTable3[bytes[12]] ^
10214
+ Crc64XzTable4[bytes[11]] ^
10215
+ Crc64XzTable5[bytes[10]] ^
10216
+ Crc64XzTable6[bytes[9]] ^
10217
+ Crc64XzTable7[bytes[8]] ^
10218
+ Crc64XzTable8[bytes[7] ^ (uint8_t)(state >> 56)] ^
10219
+ Crc64XzTable9[bytes[6] ^ (uint8_t)(state >> 48)] ^
10220
+ Crc64XzTable10[bytes[5] ^ (uint8_t)(state >> 40)] ^
10221
+ Crc64XzTable11[bytes[4] ^ (uint8_t)(state >> 32)] ^
10222
+ Crc64XzTable12[bytes[3] ^ (uint8_t)(state >> 24)] ^
10223
+ Crc64XzTable13[bytes[2] ^ (uint8_t)(state >> 16)] ^
10224
+ Crc64XzTable14[bytes[1] ^ (uint8_t)(state >> 8)] ^
10225
+ Crc64XzTable15[bytes[0] ^ (uint8_t)(state >> 0)];
10226
+ return ret;
10227
+ }
10228
+
10229
+ uint64_t CRC64xz(uint64_t state, Span<const uint8_t> buf)
10230
+ {
10231
+ state = ~state;
10232
+
10233
+ Size left = std::min(buf.len, (Size)(AlignUp(buf.ptr, 16) - buf.ptr));
10234
+ Size right = std::max(left, (Size)(AlignDown(buf.end(), 16) - buf.ptr));
10235
+
10236
+ for (Size i = 0; i < left; i++) {
10237
+ state = XzUpdate1(state, buf[i]);
10238
+ }
10239
+ for (Size i = left; i < right; i += 16) {
10240
+ state = XzUpdate16(state, buf.ptr + i);
10241
+ }
10242
+ for (Size i = right; i < buf.len; i++) {
10243
+ state = XzUpdate1(state, buf[i]);
10244
+ }
10245
+
10246
+ return ~state;
10247
+ }
10248
+
10249
+ static uint64_t NvmeUpdate1(uint64_t state, uint8_t byte)
10250
+ {
10251
+ uint64_t ret = (state >> 8) ^ Crc64NvmeTable0[byte ^ (uint8_t)state];
10252
+ return ret;
10253
+ }
10254
+
10255
+ static uint64_t NvmeUpdate16(uint64_t state, const uint8_t *bytes)
10256
+ {
10257
+ uint64_t ret = Crc64NvmeTable0[bytes[15]] ^
10258
+ Crc64NvmeTable1[bytes[14]] ^
10259
+ Crc64NvmeTable2[bytes[13]] ^
10260
+ Crc64NvmeTable3[bytes[12]] ^
10261
+ Crc64NvmeTable4[bytes[11]] ^
10262
+ Crc64NvmeTable5[bytes[10]] ^
10263
+ Crc64NvmeTable6[bytes[9]] ^
10264
+ Crc64NvmeTable7[bytes[8]] ^
10265
+ Crc64NvmeTable8[bytes[7] ^ (uint8_t)(state >> 56)] ^
10266
+ Crc64NvmeTable9[bytes[6] ^ (uint8_t)(state >> 48)] ^
10267
+ Crc64NvmeTable10[bytes[5] ^ (uint8_t)(state >> 40)] ^
10268
+ Crc64NvmeTable11[bytes[4] ^ (uint8_t)(state >> 32)] ^
10269
+ Crc64NvmeTable12[bytes[3] ^ (uint8_t)(state >> 24)] ^
10270
+ Crc64NvmeTable13[bytes[2] ^ (uint8_t)(state >> 16)] ^
10271
+ Crc64NvmeTable14[bytes[1] ^ (uint8_t)(state >> 8)] ^
10272
+ Crc64NvmeTable15[bytes[0] ^ (uint8_t)(state >> 0)];
10273
+ return ret;
10274
+ }
10275
+
10276
+ uint64_t CRC64nvme(uint64_t state, Span<const uint8_t> buf)
10277
+ {
10278
+ state = ~state;
10279
+
10280
+ Size left = std::min(buf.len, (Size)(AlignUp(buf.ptr, 16) - buf.ptr));
10281
+ Size right = std::max(left, (Size)(AlignDown(buf.end(), 16) - buf.ptr));
10282
+
10283
+ for (Size i = 0; i < left; i++) {
10284
+ state = NvmeUpdate1(state, buf[i]);
10285
+ }
10286
+ for (Size i = left; i < right; i += 16) {
10287
+ state = NvmeUpdate16(state, buf.ptr + i);
10288
+ }
10289
+ for (Size i = right; i < buf.len; i++) {
10290
+ state = NvmeUpdate1(state, buf[i]);
10291
+ }
10292
+
10293
+ return ~state;
10294
+ }
10295
+
9975
10296
  }