Skip to content

Commit

Permalink
cherry pick #12672 to release-4.0
Browse files Browse the repository at this point in the history
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
  • Loading branch information
wshwsh12 authored and ti-srebot committed May 30, 2022
1 parent efe4b13 commit 7a0714e
Showing 1 changed file with 149 additions and 0 deletions.
149 changes: 149 additions & 0 deletions components/tidb_query/src/rpn_expr/impl_math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,154 @@ thread_local! {
static MYSQL_RNG: RefCell<MySQLRng> = RefCell::new(MySQLRng::new())
}

<<<<<<< HEAD:components/tidb_query/src/rpn_expr/impl_math.rs
=======
#[derive(Copy, Clone)]
struct IntWithSign(u64, bool);

impl IntWithSign {
fn from_int(num: Int) -> IntWithSign {
IntWithSign(num.wrapping_abs() as u64, num < 0)
}

fn from_signed_uint(num: u64, is_neg: bool) -> IntWithSign {
IntWithSign(num, is_neg)
}

// Shrink num to fit the boundary of i64.
fn shrink_from_signed_uint(num: u64, is_neg: bool) -> IntWithSign {
let value = if is_neg {
num.min(-Int::min_value() as u64)
} else {
num.min(Int::max_value() as u64)
};
IntWithSign::from_signed_uint(value, is_neg)
}

fn format_radix(mut x: u64, radix: u32) -> String {
let mut r = vec![];
loop {
let m = x % u64::from(radix);
x /= u64::from(radix);
r.push(
std::char::from_digit(m as u32, radix)
.unwrap()
.to_ascii_uppercase(),
);
if x == 0 {
break;
}
}
r.iter().rev().collect::<String>()
}

fn format_to_base(self, to_base: IntWithSign) -> String {
let IntWithSign(value, is_neg) = self;
let IntWithSign(to_base, should_ignore_sign) = to_base;
let mut real_val = value as i64;
if is_neg && !should_ignore_sign {
real_val = -real_val;
}
let mut ret = IntWithSign::format_radix(real_val as u64, to_base as u32);
if is_neg && should_ignore_sign {
ret.insert(0, '-');
}
ret
}
}

fn is_valid_base(base: IntWithSign) -> bool {
let IntWithSign(num, _) = base;
(2..=36).contains(&num)
}

fn extract_num_str(s: &str, from_base: IntWithSign) -> Option<(String, bool)> {
let mut iter = s.chars().peekable();
let head = *iter.peek()?;
let mut is_neg = false;
if head == '+' || head == '-' {
is_neg = head == '-';
iter.next();
}
let IntWithSign(base, _) = from_base;
let s = iter
.take_while(|x| x.is_digit(base as u32))
.collect::<String>();
if s.is_empty() {
None
} else {
Some((s, is_neg))
}
}

fn extract_num(num_s: &str, is_neg: bool, from_base: IntWithSign) -> IntWithSign {
let IntWithSign(from_base, signed) = from_base;
let value = u64::from_str_radix(num_s, from_base as u32).unwrap();
if signed {
IntWithSign::shrink_from_signed_uint(value, is_neg)
} else {
IntWithSign::from_signed_uint(value, is_neg)
}
}

// Returns (isize, is_positive): convert an i64 to usize, and whether the input is positive
//
// # Examples
// ```
// assert_eq!(i64_to_usize(1_i64, false), (1_usize, true));
// assert_eq!(i64_to_usize(1_i64, false), (1_usize, true));
// assert_eq!(i64_to_usize(-1_i64, false), (1_usize, false));
// assert_eq!(i64_to_usize(u64::max_value() as i64, true), (u64::max_value() as usize, true));
// assert_eq!(i64_to_usize(u64::max_value() as i64, false), (1_usize, false));
// ```
#[inline]
pub fn i64_to_usize(i: i64, is_unsigned: bool) -> (usize, bool) {
if is_unsigned {
(i as u64 as usize, true)
} else if i >= 0 {
(i as usize, true)
} else {
let i = if i == i64::min_value() {
i64::max_value() as usize + 1
} else {
-i as usize
};
(i, false)
}
}

pub struct MySQLRng {
seed1: u32,
seed2: u32,
}

impl MySQLRng {
fn new() -> Self {
let current_time = time::get_time();
let nsec = i64::from(current_time.nsec);
Self::new_with_seed(nsec)
}

fn new_with_seed(seed: i64) -> Self {
let seed1 = (seed.wrapping_mul(0x10001).wrapping_add(55555555)) as u32 % MAX_RAND_VALUE;
let seed2 = (seed.wrapping_mul(0x10000001)) as u32 % MAX_RAND_VALUE;
MySQLRng { seed1, seed2 }
}

fn gen(&mut self) -> f64 {
self.seed1 = (self.seed1 * 3 + self.seed2) % MAX_RAND_VALUE;
self.seed2 = (self.seed1 + self.seed2 + 33) % MAX_RAND_VALUE;
f64::from(self.seed1) / f64::from(MAX_RAND_VALUE)
}
}

impl Default for MySQLRng {
fn default() -> Self {
Self::new()
}
}

>>>>>>> 62d777760... expr: fix tikv crash when conv empty string (#12672):components/tidb_query_expr/src/impl_math.rs
#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down Expand Up @@ -1380,6 +1528,7 @@ mod tests {
("16九a", 10, 8, "20"),
("+", 10, 8, "0"),
("-", 10, 8, "0"),
("", 2, 16, "0"),
];
for (n, f, t, e) in tests {
let n = Some(n.as_bytes().to_vec());
Expand Down

0 comments on commit 7a0714e

Please sign in to comment.