From f675b04ed89a7ffb896426850cff70cd4c920011 Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Tue, 19 Apr 2022 16:54:23 +0800 Subject: [PATCH] ordering and comparator --- src/relation.rs | 3 +- src/relation/key_order.rs | 62 ++++++++++++++++++++++++++++ src/relation/tuple.rs | 75 +++++++++++++++++++++++++--------- src/relation/value.rs | 85 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 200 insertions(+), 25 deletions(-) create mode 100644 src/relation/key_order.rs diff --git a/src/relation.rs b/src/relation.rs index 4784ae06..6f6c76a9 100644 --- a/src/relation.rs +++ b/src/relation.rs @@ -1,2 +1,3 @@ pub mod tuple; -pub mod value; \ No newline at end of file +pub mod value; +pub mod key_order; \ No newline at end of file diff --git a/src/relation/key_order.rs b/src/relation/key_order.rs new file mode 100644 index 00000000..47b58fe4 --- /dev/null +++ b/src/relation/key_order.rs @@ -0,0 +1,62 @@ +use std::cmp::Ordering; +use crate::relation::tuple::Tuple; + +pub fn compare(a: &[u8], b: &[u8]) -> i8 { + let ta = Tuple::new(a); + let tb = Tuple::new(b); + match ta.get_prefix().cmp(&tb.get_prefix()) { + Ordering::Less => return -1, + Ordering::Greater => return 1, + Ordering::Equal => {} + } + let mut ia = ta.iter(); + let mut ib = tb.iter(); + loop { + match (ia.next(), ib.next()) { + (None, None) => return 0, + (None, Some(_)) => return -1, + (Some(_), None) => return 1, + (Some(va), Some(vb)) => { + match va.cmp(&vb) { + Ordering::Less => return -1, + Ordering::Greater => return 1, + Ordering::Equal => {} + } + } + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + use crate::relation::key_order::compare; + use crate::relation::tuple::Tuple; + use crate::relation::value::Value; + + #[test] + fn ordering() { + let mut t = Tuple::with_prefix(0); + let t2 = Tuple::with_prefix(123); + assert_eq!(compare(t.as_ref(), t.as_ref()), 0); + assert_eq!(compare(t.as_ref(), t2.as_ref()), -1); + assert_eq!(compare(t2.as_ref(), t.as_ref()), 1); + let mut t2 = Tuple::with_prefix(0); + t.push_str("aaa"); + t2.push_str("aaac"); + assert_eq!(compare(t.as_ref(), t2.as_ref()), -1); + let mut t2 = Tuple::with_prefix(0); + t2.push_str("aaa"); + t2.push_null(); + assert_eq!(compare(t.as_ref(), t2.as_ref()), -1); + t.push_null(); + assert_eq!(compare(t.as_ref(), t2.as_ref()), 0); + t.push_int(-123); + t2.push_int(123); + assert_eq!(compare(t.as_ref(), t2.as_ref()), -1); + assert_eq!(compare(t.as_ref(), t.as_ref()), 0); + let vals: Value = vec![().into(), BTreeMap::new().into(), 1e23.into(), false.into(), "xxyx".into()].into(); + t.push_value(&vals); + assert_eq!(compare(t.as_ref(), t.as_ref()), 0); + } +} \ No newline at end of file diff --git a/src/relation/tuple.rs b/src/relation/tuple.rs index e6c8e211..c9119cc2 100644 --- a/src/relation/tuple.rs +++ b/src/relation/tuple.rs @@ -1,6 +1,5 @@ use std::borrow::{Cow}; use std::cell::RefCell; -use std::cmp::Ordering; use std::collections::BTreeMap; use uuid::Uuid; use crate::relation::value::{EdgeDir, Tag, Value}; @@ -13,17 +12,28 @@ pub struct Tuple idx_cache: RefCell>, } +impl AsRef<[u8]> for Tuple where T: AsRef<[u8]> { + fn as_ref(&self) -> &[u8] { + self.data.as_ref() + } +} + const PREFIX_LEN: usize = 4; impl> Tuple { #[inline] - fn new(data: T) -> Self { + pub fn new(data: T) -> Self { Self { data, idx_cache: RefCell::new(vec![]), } } + #[inline] + pub fn get_prefix(&self) -> u32 { + u32::from_be_bytes(self.data.as_ref()[0..4].try_into().unwrap()) + } + #[inline] fn all_cached(&self) -> bool { match self.idx_cache.borrow().last() { @@ -106,7 +116,7 @@ impl> Tuple { } } #[inline] - pub fn parse_value_at(&self, pos: usize) -> (Value, usize) { + fn parse_value_at(&self, pos: usize) -> (Value, usize) { let data = self.data.as_ref(); let start = pos + 1; let (nxt, val): (usize, Value) = match Tag::from(data[pos]) { @@ -170,10 +180,31 @@ impl> Tuple { }; (val, nxt) } + pub fn iter(&self) -> TupleIter { + TupleIter { + tuple: self, + pos: 4, + } + } } -impl Tuple<&[u8]> {} +pub struct TupleIter<'a, T: AsRef<[u8]>> { + tuple: &'a Tuple, + pos: usize, +} +impl<'a, T: AsRef<[u8]>> Iterator for TupleIter<'a, T> { + type Item = Value<'a>; + + fn next(&mut self) -> Option { + if self.pos == self.tuple.data.as_ref().len() { + return None; + } + let (v, pos) = self.tuple.parse_value_at(self.pos); + self.pos = pos; + Some(v) + } +} impl Tuple> { #[inline] @@ -246,7 +277,7 @@ impl Tuple> { Value::EdgeDir(e) => self.push_edge_dir(*e), Value::UInt(u) => self.push_uint(*u), Value::Int(i) => self.push_int(*i), - Value::Float(f) => self.push_float(*f), + Value::Float(f) => self.push_float(f.into_inner()), Value::Uuid(u) => self.push_uuid(*u), Value::Text(t) => self.push_str(t), Value::List(l) => { @@ -309,7 +340,6 @@ impl Tuple> { }; self.push_varint(u); } - } impl> PartialEq for Tuple { @@ -321,20 +351,6 @@ impl> PartialEq for Tuple { impl> Eq for Tuple {} -impl> PartialOrd for Tuple { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl> Ord for Tuple { - #[inline] - fn cmp(&self, other: &Self) -> Ordering { - todo!() - } -} - #[cfg(test)] mod tests { @@ -432,5 +448,24 @@ mod tests { assert_eq!(Value::from(-123345i64), t.get(7).unwrap()); assert_eq!(Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), t.get(10).unwrap()); assert_eq!(None, t.get(13131)); + + println!("{:?}", t.iter().collect::>()); + for v in t.iter() { + println!("{}", v); + } + } + + /* + #[test] + fn lifetime() { + let v; + { + let s : Vec = vec![]; + let s = s.as_slice(); + let p = Tuple::new(s); + v = p.get(0); + } + println!("{:?}", v); } + */ } \ No newline at end of file diff --git a/src/relation/value.rs b/src/relation/value.rs index 93d21c5a..fad27d56 100644 --- a/src/relation/value.rs +++ b/src/relation/value.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; use std::collections::BTreeMap; +use std::fmt::{Display, Formatter, Write}; +use ordered_float::OrderedFloat; use uuid::Uuid; #[repr(u8)] @@ -66,21 +68,21 @@ impl From for Tag { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd)] pub enum EdgeDir { Fwd, Bwd, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Ord, PartialOrd, Eq)] pub enum Value<'a> { Null, Bool(bool), EdgeDir(EdgeDir), UInt(u64), Int(i64), - Float(f64), + Float(OrderedFloat), Uuid(Uuid), Text(Cow<'a, str>), List(Vec>), @@ -89,7 +91,7 @@ pub enum Value<'a> { pub type StaticValue = Value<'static>; -impl <'a> Value<'a> { +impl<'a> Value<'a> { #[inline] pub fn to_static(self) -> StaticValue { match self { @@ -147,6 +149,14 @@ impl From for StaticValue { impl From for StaticValue { #[inline] fn from(f: f64) -> Self { + Value::Float(f.into()) + } +} + + +impl From> for StaticValue { + #[inline] + fn from(f: OrderedFloat) -> Self { Value::Float(f) } } @@ -185,3 +195,70 @@ impl<'a> From, Value<'a>>> for Value<'a> { Value::Dict(m) } } + + +impl<'a> Display for Value<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Value::Null => { f.write_str("null")?; } + Value::Bool(b) => { f.write_str(if *b { "true" } else { "false" })?; } + Value::EdgeDir(d) => { + f.write_str(match d { + EdgeDir::Fwd => "fwd", + EdgeDir::Bwd => "bwd" + })?; + } + Value::UInt(u) => { + f.write_str(&u.to_string())?; + f.write_str("u")?; + } + Value::Int(i) => { f.write_str(&i.to_string())?; } + Value::Float(n) => { f.write_str(&format!("{:e}", n.into_inner()))?; } + Value::Uuid(u) => { f.write_str(&u.to_string())?; } + Value::Text(t) => { + f.write_char('"')?; + for char in t.chars() { + match char { + '"' => { f.write_str("\\\"")?; } + '\\' => { f.write_str("\\\\")?; } + '/' => { f.write_str("\\/")?; } + '\x08' => { f.write_str("\\b")?; } + '\x0c' => { f.write_str("\\f")?; } + '\n' => { f.write_str("\\n")?; } + '\r' => { f.write_str("\\r")?; } + '\t' => { f.write_str("\\t")?; } + c => { f.write_char(c)?; } + } + } + f.write_char('"')?; + } + Value::List(l) => { + f.write_char('[')?; + let mut first = true; + for v in l.iter() { + if !first { + f.write_char(',')?; + } + Display::fmt(v, f)?; + first = false; + } + f.write_char(']')?; + } + Value::Dict(d) => { + f.write_char('{')?; + let mut first = true; + for (k, v) in d.iter() { + if !first { + f.write_char(',')?; + } + Display::fmt(&Value::Text(k.clone()), f)?; + f.write_char(':')?; + Display::fmt(v, f)?; + first = false; + } + f.write_char('}')?; + } + } + Ok(()) + } +} \ No newline at end of file