use crate::{distribution::Distribution, text::TextPool};
use std::fmt::Display;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct RowRandomInt {
seed: i64,
usage: i32,
seeds_per_row: i32,
}
impl RowRandomInt {
const MULTIPLIER: i64 = 16807;
const MODULUS: i64 = 2147483647;
const DEFAULT_SEED: i64 = 19620718;
pub fn new(seed: i64, seeds_per_row: i32) -> Self {
Self {
seed,
usage: 0,
seeds_per_row,
}
}
pub fn new_with_default_seed_and_column_number(column_number: i32, seeds_per_row: i32) -> Self {
Self::new_with_column_number(column_number, Self::DEFAULT_SEED, seeds_per_row)
}
pub fn new_with_column_number(column_number: i32, seed: i64, seeds_per_row: i32) -> Self {
Self {
seed: seed + column_number as i64 * (Self::MODULUS / 799),
seeds_per_row,
usage: 0,
}
}
pub fn next_int(&mut self, lower_bound: i32, upper_bound: i32) -> i32 {
let _ = self.next_rand();
let range = (upper_bound - lower_bound).wrapping_add(1) as f64;
let value = ((1.0 * (self.seed as f64) / Self::MODULUS as f64) * range) as i32;
lower_bound + value
}
pub fn next_rand(&mut self) -> i64 {
self.seed = (self.seed * Self::MULTIPLIER) % Self::MODULUS;
self.usage += 1;
self.seed
}
pub fn row_finished(&mut self) {
self.advance_seed((self.seeds_per_row - self.usage) as i64);
self.usage = 0;
}
pub fn advance_rows(&mut self, row_count: i64) {
if self.usage != 0 {
self.row_finished();
}
self.advance_seed(self.seeds_per_row as i64 * row_count);
}
fn advance_seed(&mut self, count: i64) {
let mut multiplier = Self::MULTIPLIER;
let mut count = count;
while count > 0 {
if count % 2 != 0 {
self.seed = (multiplier * self.seed) % Self::MODULUS;
}
count /= 2;
multiplier = (multiplier * multiplier) % Self::MODULUS;
}
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct RowRandomLong {
seed: i64,
seeds_per_row: i32,
usage: i32,
}
impl RowRandomLong {
const MULTIPLIER: i64 = 6364136223846793005;
const INCREMENT: i64 = 1;
const MULTIPLIER_32: i64 = 16807;
const MODULUS_32: i64 = 2147483647;
pub fn new(seed: i64, seeds_per_row: i32) -> Self {
Self {
seed,
seeds_per_row,
usage: 0,
}
}
pub fn next_long(&mut self, lower_bound: i64, upper_bound: i64) -> i64 {
self.next_rand();
let value_in_range = (self.seed.abs()) % (upper_bound - lower_bound + 1);
lower_bound + value_in_range
}
fn next_rand(&mut self) -> i64 {
self.seed = (self.seed.wrapping_mul(Self::MULTIPLIER)) + Self::INCREMENT;
self.usage += 1;
self.seed
}
pub fn row_finished(&mut self) {
self.advance_seed_32((self.seeds_per_row - self.usage) as i64);
self.usage = 0;
}
pub fn advance_rows(&mut self, row_count: i64) {
if self.usage != 0 {
self.row_finished();
}
self.advance_seed_32((self.seeds_per_row as i64) * row_count);
}
fn advance_seed_32(&mut self, mut count: i64) {
let mut multiplier: i64 = Self::MULTIPLIER_32;
while count > 0 {
if count % 2 != 0 {
self.seed = (multiplier * self.seed) % Self::MODULUS_32;
}
count /= 2;
multiplier = (multiplier * multiplier) % Self::MODULUS_32;
}
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct RandomBoundedInt {
lower_bound: i32,
upper_bound: i32,
random_int: RowRandomInt,
}
impl RandomBoundedInt {
pub fn new(seed: i64, lower_bound: i32, upper_bound: i32) -> Self {
Self {
lower_bound,
upper_bound,
random_int: RowRandomInt::new(seed, 1),
}
}
pub fn new_with_seeds_per_row(
seed: i64,
lower_bound: i32,
upper_bound: i32,
seeds_per_row: i32,
) -> Self {
Self {
lower_bound,
upper_bound,
random_int: RowRandomInt::new(seed, seeds_per_row),
}
}
pub fn next_value(&mut self) -> i32 {
self.random_int.next_int(self.lower_bound, self.upper_bound)
}
pub fn advance_rows(&mut self, row_count: i64) {
self.random_int.advance_rows(row_count);
}
pub fn row_finished(&mut self) {
self.random_int.row_finished();
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct RandomBoundedLong {
use_64bits: bool,
lower_bound: i64,
upper_bound: i64,
random_long: RowRandomLong,
random_int: RowRandomInt,
}
impl RandomBoundedLong {
pub fn new(seed: i64, use_64bits: bool, lower_bound: i64, upper_bound: i64) -> Self {
Self {
lower_bound,
use_64bits,
upper_bound,
random_long: RowRandomLong::new(seed, 1),
random_int: RowRandomInt::new(seed, 1),
}
}
pub fn new_with_seeds_per_row(
seed: i64,
use_64bits: bool,
lower_bound: i64,
upper_bound: i64,
seeds_per_row: i32,
) -> Self {
Self {
use_64bits,
lower_bound,
upper_bound,
random_long: RowRandomLong::new(seed, seeds_per_row),
random_int: RowRandomInt::new(seed, seeds_per_row),
}
}
pub fn next_value(&mut self) -> i64 {
if self.use_64bits {
self.random_long
.next_long(self.lower_bound, self.upper_bound)
} else {
self.random_int
.next_int(self.lower_bound as i32, self.upper_bound as i32) as i64
}
}
pub fn advance_rows(&mut self, row_count: i64) {
if self.use_64bits {
self.random_long.advance_rows(row_count);
} else {
self.random_int.advance_rows(row_count);
}
}
pub fn row_finished(&mut self) {
if self.use_64bits {
self.random_long.row_finished();
} else {
self.random_int.row_finished();
}
}
}
#[derive(Debug)]
pub struct RandomAlphaNumeric {
inner: RowRandomInt,
min_length: i32,
max_length: i32,
}
impl RandomAlphaNumeric {
const ALPHA_NUMERIC: &'static [u8] =
b"0123456789abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ,";
const LOW_LENGTH_MULTIPLIER: f64 = 0.4;
const HIGH_LENGTH_MULTIPLIER: f64 = 1.6;
const USAGE_PER_ROW: i32 = 9;
pub fn new(seed: i64, average_length: i32) -> Self {
Self::new_with_expected_row_count(seed, average_length, 1)
}
pub fn new_with_expected_row_count(seed: i64, average_length: i32, seeds_per_row: i32) -> Self {
let min_length = (average_length as f64 * Self::LOW_LENGTH_MULTIPLIER) as i32;
let max_length = (average_length as f64 * Self::HIGH_LENGTH_MULTIPLIER) as i32;
Self {
inner: RowRandomInt::new(seed, Self::USAGE_PER_ROW * seeds_per_row),
min_length,
max_length,
}
}
pub fn next_value(&mut self) -> RandomAlphaNumericInstance {
let length = self.inner.next_int(self.min_length, self.max_length) as usize;
RandomAlphaNumericInstance {
length,
snapshot: self.inner,
}
}
pub fn advance_rows(&mut self, row_count: i64) {
self.inner.advance_rows(row_count);
}
pub fn row_finished(&mut self) {
self.inner.row_finished();
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RandomAlphaNumericInstance {
length: usize,
snapshot: RowRandomInt,
}
impl Display for RandomAlphaNumericInstance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut stack_buffer = [0u8; 64];
let mut heap_buffer = Vec::new();
let buffer = if self.length <= stack_buffer.len() {
&mut stack_buffer[0..self.length]
} else {
heap_buffer.resize(self.length, 0);
&mut heap_buffer
};
let mut generator = self.snapshot;
let mut char_index = 0;
#[allow(clippy::needless_range_loop)]
for i in 0..self.length {
if i % 5 == 0 {
char_index = generator.next_int(0, i32::MAX) as i64;
}
let char_pos = (char_index & 0x3f) as usize;
buffer[i] = RandomAlphaNumeric::ALPHA_NUMERIC[char_pos];
char_index >>= 6;
}
let s = unsafe { std::str::from_utf8_unchecked(buffer) };
f.write_str(s)?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RandomPhoneNumber {
inner: RowRandomInt,
}
impl RandomPhoneNumber {
const NATIONS_MAX: i32 = 90;
pub fn new(seed: i64) -> Self {
Self::new_with_expected_row_count(seed, 1)
}
pub fn new_with_expected_row_count(seed: i64, seeds_per_row: i32) -> Self {
Self {
inner: RowRandomInt::new(seed, 3 * seeds_per_row),
}
}
pub fn next_value(&mut self, nation_key: i64) -> PhoneNumberInstance {
PhoneNumberInstance {
country_code: 10 + (nation_key % Self::NATIONS_MAX as i64) as i32,
local1: self.inner.next_int(100, 999),
local2: self.inner.next_int(100, 999),
local3: self.inner.next_int(1000, 9999),
}
}
pub fn advance_rows(&mut self, row_count: i64) {
self.inner.advance_rows(row_count);
}
pub fn row_finished(&mut self) {
self.inner.row_finished();
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhoneNumberInstance {
country_code: i32,
local1: i32,
local2: i32,
local3: i32,
}
impl Display for PhoneNumberInstance {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{:02}-{:03}-{:03}-{:04}",
self.country_code, self.local1, self.local2, self.local3
)
}
}
#[derive(Debug, Clone)]
pub struct RandomString<'a> {
inner: RowRandomInt,
distribution: &'a Distribution,
}
impl<'a> RandomString<'a> {
pub fn new(seed: i64, distribution: &'a Distribution) -> Self {
Self::new_with_expected_row_count(seed, distribution, 1)
}
pub fn new_with_expected_row_count(
seed: i64,
distribution: &'a Distribution,
seeds_per_row: i32,
) -> Self {
Self {
inner: RowRandomInt::new(seed, seeds_per_row),
distribution,
}
}
pub fn next_value(&mut self) -> &'a str {
self.distribution.random_value(&mut self.inner)
}
pub fn advance_rows(&mut self, row_count: i64) {
self.inner.advance_rows(row_count);
}
pub fn row_finished(&mut self) {
self.inner.row_finished();
}
}
#[derive(Debug)]
pub struct RandomStringSequence<'a> {
inner: RowRandomInt,
count: i32,
distribution: &'a Distribution,
}
impl<'a> RandomStringSequence<'a> {
pub fn new(seed: i64, count: i32, distribution: &'a Distribution) -> Self {
Self::new_with_expected_row_count(seed, count, distribution, 1)
}
pub fn new_with_expected_row_count(
seed: i64,
count: i32,
distribution: &'a Distribution,
seeds_per_row: i32,
) -> Self {
Self {
inner: RowRandomInt::new(seed, distribution.size() as i32 * seeds_per_row),
count,
distribution,
}
}
pub fn next_value(&mut self) -> StringSequenceInstance<'a> {
let mut values: Vec<&str> = self.distribution.get_values().to_vec();
for current_position in 0..self.count {
let swap_position =
self.inner
.next_int(current_position, values.len() as i32 - 1) as usize;
values.swap(current_position as usize, swap_position);
}
values.truncate(self.count as usize);
StringSequenceInstance { values }
}
pub fn advance_rows(&mut self, row_count: i64) {
self.inner.advance_rows(row_count);
}
pub fn row_finished(&mut self) {
self.inner.row_finished();
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct StringSequenceInstance<'a> {
values: Vec<&'a str>,
}
impl Display for StringSequenceInstance<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iter = self.values.iter();
if let Some(first) = iter.next() {
write!(f, "{}", first)?;
}
for value in iter {
write!(f, " {}", value)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct RandomText<'a> {
inner: RowRandomInt,
text_pool: &'a TextPool,
min_length: i32,
max_length: i32,
}
impl<'a> RandomText<'a> {
const LOW_LENGTH_MULTIPLIER: f64 = 0.4;
const HIGH_LENGTH_MULTIPLIER: f64 = 1.6;
pub fn new(seed: i64, text_pool: &'a TextPool, average_text_length: f64) -> Self {
Self::new_with_expected_row_count(seed, text_pool, average_text_length, 1)
}
pub fn new_with_expected_row_count(
seed: i64,
text_pool: &'a TextPool,
average_text_length: f64,
expected_row_count: i32,
) -> Self {
Self {
inner: RowRandomInt::new(seed, expected_row_count * 2),
text_pool,
min_length: (average_text_length * Self::LOW_LENGTH_MULTIPLIER) as i32,
max_length: (average_text_length * Self::HIGH_LENGTH_MULTIPLIER) as i32,
}
}
pub fn next_value(&mut self) -> &'a str {
let offset = self
.inner
.next_int(0, self.text_pool.size() - self.max_length);
let length = self.inner.next_int(self.min_length, self.max_length);
self.text_pool.text(offset, offset + length)
}
pub fn advance_rows(&mut self, row_count: i64) {
self.inner.advance_rows(row_count);
}
pub fn row_finished(&mut self) {
self.inner.row_finished();
}
}
#[cfg(test)]
mod test {
use super::*;
use std::collections::HashSet;
#[test]
fn test_small_random_alpha_numeric() {
RandomAlphaNumericTest {
average_length: 10,
num_rows: 100,
expected_average_length: 10,
}
.assert()
}
#[test]
fn test_large_random_alpha_numeric() {
RandomAlphaNumericTest {
average_length: 100,
num_rows: 100,
expected_average_length: 102,
}
.assert()
}
struct RandomAlphaNumericTest {
average_length: i32,
num_rows: usize,
expected_average_length: usize,
}
impl RandomAlphaNumericTest {
fn assert(self) {
let Self {
average_length,
num_rows,
expected_average_length,
} = self;
let mut generator = RandomAlphaNumeric::new(1, average_length);
let mut values = HashSet::new();
let mut total_len = 0;
for _ in 0..num_rows {
let value = generator.next_value().to_string();
total_len += value.len();
assert!(values.insert(value)); }
assert_eq!(total_len / num_rows, expected_average_length);
}
}
}