Repository: apache/arrow
File: cpp/src/arrow/testing/random.cc (C++)

Code before:

void rand_month_day_nanos(int64_t N,
                          std::vector<MonthDayNanoIntervalType::MonthDayNanos>* out) {
  const int random_seed = 0;
  arrow::random::pcg32 gen(random_seed);
  std::uniform_int_distribution<int64_t> d(std::numeric_limits<int64_t>::min(),
                                           std::numeric_limits<int64_t>::max());
  out->resize(N, {});
  std::generate(out->begin(), out->end(), [&d, &gen] {
    MonthDayNanoIntervalType::MonthDayNanos tmp;
    tmp.months = static_cast<int32_t>(d(gen));
    tmp.days = static_cast<int32_t>(d(gen));
    tmp.nanoseconds = d(gen);
    return tmp;
  });
}

std::string RandomUtf8String(int num_chars) {
  std::random_device rd;
  std::default_random_engine gen(rd());
  std::string s;
  s.reserve(num_chars * 3);  // Reserve for average 3 bytes per codepoint

  for (int i = 0; i < num_chars; ++i) {
    uint32_t codepoint;
    std::uniform_int_distribution<uint32_t> plane_dist(0, 3);
    uint32_t plane = plane_dist(gen);

    if (plane == 0) {
      // Basic Multilingual Plane (BMP): U+0000 to U+FFFF
      // Exclude surrogate code points (U+D800 to U+DFFF)
      // https://www.unicode.org/versions/Unicode15.1.0/ch03.pdf (Section 3.8, D71)
      // Exclude control chars below U+0020 for readability
      // Generate from two ranges with equal probability (overrepresents the smaller
      // upper range):
      // - Lower: U+0020 to U+D7FF (55,776 values, 50% selection probability)
      // - Upper: U+E000 to U+FFFD (8,190 values, 50% selection probability)
      if (std::bernoulli_distribution(0.5)(gen)) {
        // Lower range: U+0020 to U+D7FF (before surrogate range)
        codepoint = std::uniform_int_distribution<uint32_t>(0x0020, 0xD7FF)(gen);
      } else {
        // Upper range: U+E000 to U+FFFD (after surrogate range)
        // Note: Stops at U+FFFD to exclude noncharacters U+FFFE and U+FFFF
        // Other noncharacters (U+FDD0-U+FDEF, plane-ending pairs) are included
        // as they are valid Unicode scalar values per the Unicode Standard
        codepoint = std::uniform_int_distribution<uint32_t>(0xE000, 0xFFFD)(gen);
      }
    } else if (plane == 1) {
      // Supplementary Multilingual Plane (SMP): U+10000 to U+1FFFF
      // https://www.unicode.org/roadmaps/smp/
      codepoint = std::uniform_int_distribution<uint32_t>(0x10000, 0x1FFFF)(gen);

Review comment (performance):
I don't know how expensive it is to instantiate all those distributions at each loop iteration. Perhaps they can be moved out of the loop.

Code after:

void rand_month_day_nanos(int64_t N,
                          std::vector<MonthDayNanoIntervalType::MonthDayNanos>* out) {
  const int random_seed = 0;
  arrow::random::pcg32 gen(random_seed);
  std::uniform_int_distribution<int64_t> d(std::numeric_limits<int64_t>::min(),
                                           std::numeric_limits<int64_t>::max());
  out->resize(N, {});
  std::generate(out->begin(), out->end(), [&d, &gen] {
    MonthDayNanoIntervalType::MonthDayNanos tmp;
    tmp.months = static_cast<int32_t>(d(gen));
    tmp.days = static_cast<int32_t>(d(gen));
    tmp.nanoseconds = d(gen);
    return tmp;
  });
}

std::string RandomUtf8String(random::SeedType seed, int num_chars) {
  arrow::random::pcg32 gen(seed);
  std::string s;
  s.reserve(num_chars * 3);  // Reserve for average 3 bytes per codepoint

  std::uniform_int_distribution<uint32_t> plane_dist(0, 3);
  std::bernoulli_distribution bmp_range_dist(0.5);
  std::uniform_int_distribution<uint32_t> bmp_lower_dist(0x0020, 0xD7FF);
  std::uniform_int_distribution<uint32_t> bmp_upper_dist(0xE000, 0xFFFD);
  std::uniform_int_distribution<uint32_t> smp_dist(0x10000, 0x1FFFF);
  std::uniform_int_distribution<uint32_t> sip_dist(0x20000, 0x2FFFF);
  std::uniform_int_distribution<uint32_t> high_plane_dist(0x30000, 0x10FFFF);

  for (int i = 0; i < num_chars; ++i) {
    uint32_t codepoint;
    uint32_t plane = plane_dist(gen);

    if (plane == 0) {
      // Basic Multilingual Plane (BMP): U+0000 to U+FFFF
      // Exclude surrogate code points (U+D800 to U+DFFF)
      // https://www.unicode.org/versions/Unicode15.1.0/ch03.pdf (Section 3.8, D71)
      // Exclude control chars below U+0020 for readability
      // Generate from two ranges with equal probability (overrepresents the smaller
      // upper range):
      // - Lower: U+0020 to U+D7FF (55,776 values, 50% selection probability)
      // - Upper: U+E000 to U+FFFD (8,190 values, 50% selection probability)
      if (bmp_range_dist(gen)) {
        // Lower range: U+0020 to U+D7FF (before surrogate range)
        codepoint = bmp_lower_dist(gen);
      } else {
        // Upper range: U+E000 to U+FFFD (after surrogate range)
        // Note: Stops at U+FFFD to exclude noncharacters U+FFFE and U+FFFF
        // Other noncharacters (U+FDD0-U+FDEF, plane-ending pairs) are included
        // as they are valid Unicode scalar values per the Unicode Standard