///|
// Strategy: sort-fractional-fields
///|
// Borrow decimal digits without converting them to a bounded numeric type.
priv struct DecimalKey {
negative : Bool
integer : BytesView
fraction : BytesView
}
///|
fn decimal_key(key : BytesView) -> DecimalKey {
let mut i = 0
while i < key.length() && byte_is_blank(key[i]) {
i += 1
}
let negative = i < key.length() && key[i] == b'-'
if negative {
i += 1
}
while i < key.length() && key[i] == b'0' {
i += 1
}
let start = i
while i < key.length() && byte_is_digit(key[i]) {
i += 1
}
let integer = key[start:i]
if i < key.length() && key[i] == b'.' {
i += 1
}
let fraction_start = i
while i < key.length() && byte_is_digit(key[i]) {
i += 1
}
while i > fraction_start && key[i - 1] == b'0' {
i -= 1
}
let fraction = key[fraction_start:i]
{
negative: negative && (integer.length() > 0 || fraction.length() > 0),
integer,
fraction,
}
}
///|
fn DecimalKey::compare(self : DecimalKey, other : DecimalKey) -> Int32 {
if self.negative != other.negative {
return if self.negative { -1 } else { 1 }
}
let mut order = self.integer.length().compare(other.integer.length())
if order == 0 {
order = self.integer.lexical_compare(other.integer)
}
if order == 0 {
order = self.fraction.lexical_compare(other.fraction)
}
if self.negative {
-order
} else {
order
}
}
///|
fn numeric_compare(left : Bytes, right : Bytes) -> Int32 {
// This fast path is exact for at most fifteen integer digits on each side.
match (integral_prefix(left), integral_prefix(right)) {
(Some(left), Some(right)) => left.compare(right)
_ => decimal_key(left).compare(decimal_key(right))
}
}
///|
// Run records retain canonical digits, not rounded Double bits. The private
// header stores sign and integer length; input bytes cannot masquerade as it.
fn prepare_numeric_field(key : BytesView) -> Bytes {
let number = decimal_key(key)
let output = @buffer.Buffer(
size_hint=5 + number.integer.length() + number.fraction.length(),
)
output.write_byte(if number.negative { b'\x01' } else { b'\x00' })
output.write_int_le(number.integer.length())
output.write_bytes(number.integer)
output.write_bytes(number.fraction)
output.to_bytes()
}
///|
fn numeric_field_value(key : Bytes) -> DecimalKey {
let length = key[1].to_int() |
(key[2].to_int() << 8) |
(key[3].to_int() << 16) |
(key[4].to_int() << 24)
{
negative: key[0] == b'\x01',
integer: key[5:5 + length],
fraction: key[5 + length:],
}
}