From a93376445844fc0803816f4f4108da6b300eba3e Mon Sep 17 00:00:00 2001 From: gaetbout Date: Wed, 3 Apr 2024 19:46:08 +0200 Subject: [PATCH] data_structure almost working --- src/data_structures/Scarb.toml | 1 + src/data_structures/src/array_ext.cairo | 4 +- src/data_structures/src/bit_array.cairo | 75 ++++++++++++------- src/data_structures/src/byte_appender.cairo | 10 +-- src/data_structures/src/byte_array_ext.cairo | 4 +- src/data_structures/src/byte_reader.cairo | 14 ++-- src/data_structures/src/lib.cairo | 14 ++-- src/data_structures/src/queue.cairo | 4 +- src/data_structures/src/stack.cairo | 9 ++- .../src/tests/bit_array_test.cairo | 40 +++++++--- .../src/tests/byte_appender_test.cairo | 2 +- .../src/tests/byte_reader_test.cairo | 26 +++---- src/data_structures/src/vec.cairo | 16 ++-- 13 files changed, 134 insertions(+), 85 deletions(-) diff --git a/src/data_structures/Scarb.toml b/src/data_structures/Scarb.toml index 36ee1b1b..835ba1c9 100644 --- a/src/data_structures/Scarb.toml +++ b/src/data_structures/Scarb.toml @@ -3,6 +3,7 @@ name = "alexandria_data_structures" version = "0.2.0" description = "A set of Cairo data structure libraries and algorithms" homepage = "https://github.com/keep-starknet-strange/alexandria/tree/main/src/data_structures" +edition = "2023_11" [tool] fmt.workspace = true diff --git a/src/data_structures/src/array_ext.cairo b/src/data_structures/src/array_ext.cairo index 3152897c..87ca7e3d 100644 --- a/src/data_structures/src/array_ext.cairo +++ b/src/data_structures/src/array_ext.cairo @@ -1,4 +1,4 @@ -trait ArrayTraitExt { +pub trait ArrayTraitExt { fn append_all(ref self: Array, ref arr: Array); fn pop_front_n(ref self: Array, n: usize); fn reverse(self: @Array) -> Array; @@ -15,7 +15,7 @@ trait ArrayTraitExt { fn unique<+PartialEq>(self: @Array) -> Array; } -trait SpanTraitExt { +pub trait SpanTraitExt { fn pop_front_n(ref self: Span, n: usize); fn pop_back_n(ref self: Span, n: usize); fn reverse(self: Span) -> Array; diff --git a/src/data_structures/src/bit_array.cairo b/src/data_structures/src/bit_array.cairo index b9e488c0..8005944f 100644 --- a/src/data_structures/src/bit_array.cairo +++ b/src/data_structures/src/bit_array.cairo @@ -1,20 +1,20 @@ -use array::{serialize_array_helper, deserialize_array_helper}; -use byte_array::BYTES_IN_BYTES31_MINUS_ONE; -use bytes_31::{ - one_shift_left_bytes_u128, one_shift_left_bytes_felt252, bytes31, BYTES_IN_U128, - BYTES_IN_BYTES31, -}; -use integer::u512; -use serde::into_felt252_based::SerdeImpl; +use core::bytes_31::{bytes31}; +use core::integer::u512; +use core::serde::Serde; +use core::serde::into_felt252_based::SerdeImpl; const SELECT_BIT: u128 = 0b10; +const POW_2_128: felt252 = 0x100000000000000000000000000000000; +const BYTES_IN_U128: usize = 16; +const BYTES_IN_BYTES31: usize = 31; +const BYTES_IN_BYTES31_MINUS_ONE: usize = BYTES_IN_BYTES31 - 1; #[derive(Clone, Drop)] -struct BitArray { - data: Array, - current: felt252, - read_pos: usize, - write_pos: usize, +pub struct BitArray { + pub data: Array, + pub current: felt252, + pub read_pos: usize, + pub write_pos: usize, } impl BitArrayDefaultImpl of Default { @@ -23,7 +23,7 @@ impl BitArrayDefaultImpl of Default { } } -trait BitArrayTrait { +pub trait BitArrayTrait { /// Appends a single bit to the BitArray /// # Arguments /// `bit` - either true or false, representing a single bit to be appended @@ -451,21 +451,15 @@ impl BitArrayIndexView of IndexView { impl BitArraySerde of Serde { fn serialize(self: @BitArray, ref output: Array) { - self.len().serialize(ref output); - let bytes31_arr = self.data.span(); - serialize_array_helper(bytes31_arr, ref output); + self.data.serialize(ref output); output.append(*self.current); } fn deserialize(ref serialized: Span) -> Option { - let length = *serialized.pop_front()?; - let length: usize = length.try_into().unwrap(); - let length_in_felts = length / 8 / BYTES_IN_BYTES31; - let bytes31_arr = deserialize_array_helper( - ref serialized, array![], length_in_felts.into() - )?; + let bytes31_arr = Serde::>::deserialize(ref serialized)?; + let write_pos = bytes31_arr.len(); let current = *serialized.pop_front()?; - Option::Some(BitArray { data: bytes31_arr, current, read_pos: 0, write_pos: length }) + Option::Some(BitArray { data: bytes31_arr, current, read_pos: 0, write_pos }) } } @@ -489,7 +483,7 @@ fn shift_bit(number: usize) -> u8 { } else if number == 7 { 0b10000000_u8 } else { - panic_with_felt252('invalid shift') + core::panic_with_felt252('invalid shift') } } @@ -503,3 +497,34 @@ fn select(word: felt252, byte_index: usize, bit_index: usize) -> bool { }; (shifted_bytes / shift_bit(bit_index).into()) % SELECT_BIT == 1 } + +// TODO Remove all done, it was copied from Starkware's library. There must be a better way +pub fn one_shift_left_bytes_felt252(n_bytes: usize) -> felt252 { + if n_bytes < BYTES_IN_U128 { + one_shift_left_bytes_u128(n_bytes).into() + } else { + one_shift_left_bytes_u128(n_bytes - BYTES_IN_U128).into() * POW_2_128 + } +} + +pub fn one_shift_left_bytes_u128(n_bytes: usize) -> u128 { + match n_bytes { + 0 => 0x1, + 1 => 0x100, + 2 => 0x10000, + 3 => 0x1000000, + 4 => 0x100000000, + 5 => 0x10000000000, + 6 => 0x1000000000000, + 7 => 0x100000000000000, + 8 => 0x10000000000000000, + 9 => 0x1000000000000000000, + 10 => 0x100000000000000000000, + 11 => 0x10000000000000000000000, + 12 => 0x1000000000000000000000000, + 13 => 0x100000000000000000000000000, + 14 => 0x10000000000000000000000000000, + 15 => 0x1000000000000000000000000000000, + _ => core::panic_with_felt252('n_bytes too big'), + } +} diff --git a/src/data_structures/src/byte_appender.cairo b/src/data_structures/src/byte_appender.cairo index 079ea583..d6aef1e7 100644 --- a/src/data_structures/src/byte_appender.cairo +++ b/src/data_structures/src/byte_appender.cairo @@ -1,13 +1,13 @@ use alexandria_encoding::reversible::reversing; -use byte_array::ByteArrayTrait; -use bytes_31::{one_shift_left_bytes_felt252, one_shift_left_bytes_u128}; -use integer::u512; +use core::byte_array::ByteArrayTrait; +use core::integer::u512; +use super::bit_array::{one_shift_left_bytes_felt252, one_shift_left_bytes_u128}; /// Generic support trait for appending signed and unsigned integers onto byte storage. /// There are two functions, one for each of big and little endian byte order due to /// performance considerations. The byte reversal could be used in the naïve case when /// only one implementation is worthwhile. -trait ByteAppenderSupportTrait { +pub trait ByteAppenderSupportTrait { /// Appends `bytes` data of size `count` ordered in big endian /// # Arguments /// * `bytes` - big endian ordered bytes to append @@ -61,7 +61,7 @@ impl ByteAppenderSupportByteArrayImpl of ByteAppenderSupportTrait { } } -trait ByteAppender { +pub trait ByteAppender { /// Appends an unsigned 16 bit integer encoded in big endian /// # Arguments /// * `word` - a 16 bit unsigned integer typed as u16 diff --git a/src/data_structures/src/byte_array_ext.cairo b/src/data_structures/src/byte_array_ext.cairo index 0f0d9f26..e48bfb44 100644 --- a/src/data_structures/src/byte_array_ext.cairo +++ b/src/data_structures/src/byte_array_ext.cairo @@ -1,6 +1,6 @@ use alexandria_data_structures::byte_reader::ByteReader; -impl SpanU8IntoBytearray of Into, ByteArray> { +pub impl SpanU8IntoBytearray of Into, ByteArray> { #[inline] fn into(self: Span) -> ByteArray { let mut reader = self.reader(); @@ -21,7 +21,7 @@ impl ArrayU8IntoByteArray of Into, ByteArray> { } } -impl ByteArrayIntoArrayU8 of Into> { +pub impl ByteArrayIntoArrayU8 of Into> { fn into(self: ByteArray) -> Array { let mut reader = self.reader(); let mut result = array![]; diff --git a/src/data_structures/src/byte_reader.cairo b/src/data_structures/src/byte_reader.cairo index daed23d6..f3194a19 100644 --- a/src/data_structures/src/byte_reader.cairo +++ b/src/data_structures/src/byte_reader.cairo @@ -1,13 +1,13 @@ -use bytes_31::{one_shift_left_bytes_u128, one_shift_left_bytes_felt252}; -use integer::u512; +use core::integer::u512; +use super::bit_array::{one_shift_left_bytes_felt252, one_shift_left_bytes_u128}; #[derive(Copy, Clone, Drop)] -struct ByteReaderState { - data: @T, - index: usize, +pub struct ByteReaderState { + pub data: @T, + pub index: usize, } -trait ByteReader { +pub trait ByteReader { /// Wraps the array of bytes in a ByteReader for sequential consumption of integers and/or bytes /// # Returns /// * `ByteReader` - The reader struct wrapping a read-only snapshot of this ByteArray @@ -531,7 +531,7 @@ trait Len { impl ArrayU8LenImpl of Len> { #[inline] fn len(self: @Array) -> usize { - core::array::array_len::(self) + core::array::ArrayImpl::len(self) } } diff --git a/src/data_structures/src/lib.cairo b/src/data_structures/src/lib.cairo index 89d1aaa0..83e3ad52 100644 --- a/src/data_structures/src/lib.cairo +++ b/src/data_structures/src/lib.cairo @@ -1,10 +1,10 @@ -mod array_ext; -mod bit_array; -mod byte_appender; -mod byte_array_ext; -mod byte_reader; -mod queue; -mod stack; +pub mod array_ext; +pub mod bit_array; +pub mod byte_appender; +pub mod byte_array_ext; +pub mod byte_reader; +pub mod queue; +pub mod stack; #[cfg(test)] mod tests; diff --git a/src/data_structures/src/queue.cairo b/src/data_structures/src/queue.cairo index 0c432c40..cff33e62 100644 --- a/src/data_structures/src/queue.cairo +++ b/src/data_structures/src/queue.cairo @@ -1,10 +1,10 @@ const ZERO_USIZE: usize = 0; -struct Queue { +pub struct Queue { elements: Array, } -trait QueueTrait { +pub trait QueueTrait { fn new() -> Queue; fn enqueue(ref self: Queue, value: T); fn dequeue(ref self: Queue) -> Option; diff --git a/src/data_structures/src/stack.cairo b/src/data_structures/src/stack.cairo index 13502cee..b7e0190e 100644 --- a/src/data_structures/src/stack.cairo +++ b/src/data_structures/src/stack.cairo @@ -12,8 +12,9 @@ //! Remove the item from the stack; //! let item = stack.pop(); //! ``` +use core::nullable::NullableImpl; -trait StackTrait { +pub trait StackTrait { /// Creates a new Stack instance. fn new() -> S; /// Pushes a new value onto the stack. @@ -28,7 +29,7 @@ trait StackTrait { fn is_empty(self: @S) -> bool; } -struct Felt252Stack { +pub struct Felt252Stack { elements: Felt252Dict, len: usize, } @@ -103,7 +104,7 @@ impl Felt252StackImpl< } -struct NullableStack { +pub struct NullableStack { elements: Felt252Dict>, len: usize, } @@ -122,7 +123,7 @@ impl NullableStackImpl, +Drop,> of StackTrait, T } fn push(ref self: NullableStack, value: T) { - self.elements.insert(self.len.into(), nullable_from_box(BoxTrait::new(value))); + self.elements.insert(self.len.into(), NullableImpl::new(value)); self.len += 1; } diff --git a/src/data_structures/src/tests/bit_array_test.cairo b/src/data_structures/src/tests/bit_array_test.cairo index 9cbe6f67..e8ee6d79 100644 --- a/src/data_structures/src/tests/bit_array_test.cairo +++ b/src/data_structures/src/tests/bit_array_test.cairo @@ -1,7 +1,29 @@ -use alexandria_data_structures::bit_array::{BitArray, BitArrayTrait, shift_bit}; -use bytes_31::one_shift_left_bytes_felt252; -use integer::BoundedInt; -use integer::u512; +use alexandria_data_structures::bit_array::{BitArray, BitArrayTrait, one_shift_left_bytes_felt252}; +use core::integer::BoundedInt; +use core::integer::u512; + +// TODO Copied from STD LIB +fn shift_bit(number: usize) -> u8 { + if number == 0 { + 1_u8 + } else if number == 1 { + 0b10_u8 + } else if number == 2 { + 0b100_u8 + } else if number == 3 { + 0b1000_u8 + } else if number == 4 { + 0b10000_u8 + } else if number == 5 { + 0b100000_u8 + } else if number == 6 { + 0b1000000_u8 + } else if number == 7 { + 0b10000000_u8 + } else { + core::panic_with_felt252('invalid shift') + } +} #[test] #[available_gas(30000000)] @@ -293,7 +315,7 @@ fn test_serde_serialize() { ba.serialize(ref out); let length = out.pop_front().unwrap(); let length: usize = length.try_into().unwrap(); - assert!(length == ba.len(), "len not equal"); + assert(length == ba.len(), ba.len().into()); let data: felt252 = out.pop_front().unwrap(); let expected: felt252 = BoundedInt::::max().into() - 1; let expected = expected * one_shift_left_bytes_felt252(15); @@ -327,12 +349,10 @@ fn test_serde_ser_deser() { // helpers fn sample_bit_array() -> BitArray { let sample: felt252 = BoundedInt::::max().into() - 1; - let u256 { low, high: _ } = sample.into(); - let ba = BitArray { + BitArray { data: array![], - current: low.into() * one_shift_left_bytes_felt252(15), + current: sample * one_shift_left_bytes_felt252(15), read_pos: 0, write_pos: 8 * 16, - }; - ba + } } diff --git a/src/data_structures/src/tests/byte_appender_test.cairo b/src/data_structures/src/tests/byte_appender_test.cairo index 835ee6d5..d24193fa 100644 --- a/src/data_structures/src/tests/byte_appender_test.cairo +++ b/src/data_structures/src/tests/byte_appender_test.cairo @@ -3,7 +3,7 @@ use alexandria_data_structures::tests::byte_reader_test::{ test_array_8, test_array_16, test_array_16_neg, test_array_32, test_array_64, test_byte_array_8, test_byte_array_16, test_byte_array_16_neg, test_byte_array_32, test_byte_array_64 }; -use integer::u512; +use core::integer::u512; #[test] #[available_gas(1000000)] diff --git a/src/data_structures/src/tests/byte_reader_test.cairo b/src/data_structures/src/tests/byte_reader_test.cairo index 1c203985..04998bfc 100644 --- a/src/data_structures/src/tests/byte_reader_test.cairo +++ b/src/data_structures/src/tests/byte_reader_test.cairo @@ -1,5 +1,5 @@ use alexandria_data_structures::byte_reader::ByteReader; -use integer::u512; +use core::integer::u512; #[test] #[available_gas(1000000)] @@ -500,39 +500,39 @@ fn test_byte_array_reader_equals_array_of_bytes_reader() { } // helpers -fn test_byte_array_8() -> ByteArray { +pub fn test_byte_array_8() -> ByteArray { let mut ba1 = Default::default(); ba1.append_word(0x0102030405060708, 8); ba1 } -fn test_byte_array_16() -> ByteArray { +pub fn test_byte_array_16() -> ByteArray { let mut ba1 = Default::default(); ba1.append_word(0x0102030405060708090a0b0c0d0e0f10, 16); ba1 } -fn test_byte_array_32() -> ByteArray { +pub fn test_byte_array_32() -> ByteArray { let mut ba1 = Default::default(); ba1.append_word(0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, 31); ba1.append_word(0x20, 1); ba1 } -fn test_byte_array_32_neg() -> ByteArray { +pub fn test_byte_array_32_neg() -> ByteArray { let mut ba1 = Default::default(); ba1.append_word(0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1, 31); ba1.append_word(0xe0, 1); ba1 } -fn test_byte_array_16_neg() -> ByteArray { +pub fn test_byte_array_16_neg() -> ByteArray { let mut ba1 = Default::default(); ba1.append_word(0xfffffffffffffffffffffffffffffffe, 16); ba1 } -fn test_byte_array_64() -> ByteArray { +pub fn test_byte_array_64() -> ByteArray { let mut ba1 = Default::default(); ba1.append_word(0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, 31); ba1.append_word(0x202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e, 31); @@ -540,15 +540,15 @@ fn test_byte_array_64() -> ByteArray { ba1 } -fn test_array_8() -> Array { +pub fn test_array_8() -> Array { array![1, 2, 3, 4, 5, 6, 7, 8] } -fn test_array_16() -> Array { +pub fn test_array_16() -> Array { array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] } -fn test_array_32() -> Array { +pub fn test_array_32() -> Array { array![ 1, 2, @@ -585,7 +585,7 @@ fn test_array_32() -> Array { ] } -fn test_array_32_neg() -> Array { +pub fn test_array_32_neg() -> Array { array![ 0xff, 0xfe, @@ -622,7 +622,7 @@ fn test_array_32_neg() -> Array { ] } -fn test_array_16_neg() -> Array { +pub fn test_array_16_neg() -> Array { array![ 0xff, 0xff, @@ -643,7 +643,7 @@ fn test_array_16_neg() -> Array { ] } -fn test_array_64() -> Array { +pub fn test_array_64() -> Array { array![ 1, 2, diff --git a/src/data_structures/src/vec.cairo b/src/data_structures/src/vec.cairo index eed2c782..e2a8e0b9 100644 --- a/src/data_structures/src/vec.cairo +++ b/src/data_structures/src/vec.cairo @@ -1,3 +1,5 @@ +use core::integer::u32_wrapping_add; +use core::nullable::NullableImpl; //! Vec implementation. //! //! # Example @@ -12,7 +14,7 @@ //! ... //! ``` -trait VecTrait { +pub trait VecTrait { /// Creates a new V instance. /// Returns /// * V The new vec instance. @@ -63,7 +65,7 @@ impl VecIndex> of Index { } } -struct Felt252Vec { +pub struct Felt252Vec { items: Felt252Dict, len: usize, } @@ -97,7 +99,7 @@ impl Felt252VecImpl, +Copy, +Felt252DictValue> of VecTrait, value: T) -> () { self.items.insert(self.len.into(), value); - self.len = integer::u32_wrapping_add(self.len, 1_usize); + self.len = u32_wrapping_add(self.len, 1_usize); } fn set(ref self: Felt252Vec, index: usize, value: T) { @@ -110,7 +112,7 @@ impl Felt252VecImpl, +Copy, +Felt252DictValue> of VecTrait { +pub struct NullableVec { items: Felt252Dict>, len: usize, } @@ -140,13 +142,13 @@ impl NullableVecImpl, +Copy> of VecTrait, T> { } fn push(ref self: NullableVec, value: T) -> () { - self.items.insert(self.len.into(), nullable_from_box(BoxTrait::new(value))); - self.len = integer::u32_wrapping_add(self.len, 1_usize); + self.items.insert(self.len.into(), NullableImpl::new(value)); + self.len = u32_wrapping_add(self.len, 1_usize); } fn set(ref self: NullableVec, index: usize, value: T) { assert(index < self.len(), 'Index out of bounds'); - self.items.insert(index.into(), nullable_from_box(BoxTrait::new(value))); + self.items.insert(index.into(), NullableImpl::new(value)); } fn len(self: @NullableVec) -> usize {