Skip to content

Commit

Permalink
data_structure almost working
Browse files Browse the repository at this point in the history
  • Loading branch information
gaetbout committed Apr 3, 2024
1 parent b7b1d15 commit a933764
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 85 deletions.
1 change: 1 addition & 0 deletions src/data_structures/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/data_structures/src/array_ext.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
trait ArrayTraitExt<T> {
pub trait ArrayTraitExt<T> {
fn append_all(ref self: Array<T>, ref arr: Array<T>);
fn pop_front_n(ref self: Array<T>, n: usize);
fn reverse(self: @Array<T>) -> Array<T>;
Expand All @@ -15,7 +15,7 @@ trait ArrayTraitExt<T> {
fn unique<+PartialEq<T>>(self: @Array<T>) -> Array<T>;
}

trait SpanTraitExt<T> {
pub trait SpanTraitExt<T> {
fn pop_front_n(ref self: Span<T>, n: usize);
fn pop_back_n(ref self: Span<T>, n: usize);
fn reverse(self: Span<T>) -> Array<T>;
Expand Down
75 changes: 50 additions & 25 deletions src/data_structures/src/bit_array.cairo
Original file line number Diff line number Diff line change
@@ -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<bytes31>,
current: felt252,
read_pos: usize,
write_pos: usize,
pub struct BitArray {
pub data: Array<bytes31>,
pub current: felt252,
pub read_pos: usize,
pub write_pos: usize,
}

impl BitArrayDefaultImpl of Default<BitArray> {
Expand All @@ -23,7 +23,7 @@ impl BitArrayDefaultImpl of Default<BitArray> {
}
}

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
Expand Down Expand Up @@ -451,21 +451,15 @@ impl BitArrayIndexView of IndexView<BitArray, usize, bool> {

impl BitArraySerde of Serde<BitArray> {
fn serialize(self: @BitArray, ref output: Array<felt252>) {
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<felt252>) -> Option<BitArray> {
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::<Array<bytes31>>::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 })
}
}

Expand All @@ -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')
}
}

Expand All @@ -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'),
}
}
10 changes: 5 additions & 5 deletions src/data_structures/src/byte_appender.cairo
Original file line number Diff line number Diff line change
@@ -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<T> {
pub trait ByteAppenderSupportTrait<T> {
/// Appends `bytes` data of size `count` ordered in big endian
/// # Arguments
/// * `bytes` - big endian ordered bytes to append
Expand Down Expand Up @@ -61,7 +61,7 @@ impl ByteAppenderSupportByteArrayImpl of ByteAppenderSupportTrait<ByteArray> {
}
}

trait ByteAppender<T> {
pub trait ByteAppender<T> {
/// Appends an unsigned 16 bit integer encoded in big endian
/// # Arguments
/// * `word` - a 16 bit unsigned integer typed as u16
Expand Down
4 changes: 2 additions & 2 deletions src/data_structures/src/byte_array_ext.cairo
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use alexandria_data_structures::byte_reader::ByteReader;

impl SpanU8IntoBytearray of Into<Span<u8>, ByteArray> {
pub impl SpanU8IntoBytearray of Into<Span<u8>, ByteArray> {
#[inline]
fn into(self: Span<u8>) -> ByteArray {
let mut reader = self.reader();
Expand All @@ -21,7 +21,7 @@ impl ArrayU8IntoByteArray of Into<Array<u8>, ByteArray> {
}
}

impl ByteArrayIntoArrayU8 of Into<ByteArray, Array<u8>> {
pub impl ByteArrayIntoArrayU8 of Into<ByteArray, Array<u8>> {
fn into(self: ByteArray) -> Array<u8> {
let mut reader = self.reader();
let mut result = array![];
Expand Down
14 changes: 7 additions & 7 deletions src/data_structures/src/byte_reader.cairo
Original file line number Diff line number Diff line change
@@ -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<T> {
data: @T,
index: usize,
pub struct ByteReaderState<T> {
pub data: @T,
pub index: usize,
}

trait ByteReader<T> {
pub trait ByteReader<T> {
/// 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
Expand Down Expand Up @@ -531,7 +531,7 @@ trait Len<T> {
impl ArrayU8LenImpl of Len<Array<u8>> {
#[inline]
fn len(self: @Array<u8>) -> usize {
core::array::array_len::<u8>(self)
core::array::ArrayImpl::len(self)
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/data_structures/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/data_structures/src/queue.cairo
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const ZERO_USIZE: usize = 0;

struct Queue<T> {
pub struct Queue<T> {
elements: Array<T>,
}

trait QueueTrait<T> {
pub trait QueueTrait<T> {
fn new() -> Queue<T>;
fn enqueue(ref self: Queue<T>, value: T);
fn dequeue(ref self: Queue<T>) -> Option<T>;
Expand Down
9 changes: 5 additions & 4 deletions src/data_structures/src/stack.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
//! Remove the item from the stack;
//! let item = stack.pop();
//! ```
use core::nullable::NullableImpl;

trait StackTrait<S, T> {
pub trait StackTrait<S, T> {
/// Creates a new Stack instance.
fn new() -> S;
/// Pushes a new value onto the stack.
Expand All @@ -28,7 +29,7 @@ trait StackTrait<S, T> {
fn is_empty(self: @S) -> bool;
}

struct Felt252Stack<T> {
pub struct Felt252Stack<T> {
elements: Felt252Dict<T>,
len: usize,
}
Expand Down Expand Up @@ -103,7 +104,7 @@ impl Felt252StackImpl<
}


struct NullableStack<T> {
pub struct NullableStack<T> {
elements: Felt252Dict<Nullable<T>>,
len: usize,
}
Expand All @@ -122,7 +123,7 @@ impl NullableStackImpl<T, +Copy<T>, +Drop<T>,> of StackTrait<NullableStack<T>, T
}

fn push(ref self: NullableStack<T>, 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;
}

Expand Down
40 changes: 30 additions & 10 deletions src/data_structures/src/tests/bit_array_test.cairo
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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::<u128>::max().into() - 1;
let expected = expected * one_shift_left_bytes_felt252(15);
Expand Down Expand Up @@ -327,12 +349,10 @@ fn test_serde_ser_deser() {
// helpers
fn sample_bit_array() -> BitArray {
let sample: felt252 = BoundedInt::<u128>::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
}
}
2 changes: 1 addition & 1 deletion src/data_structures/src/tests/byte_appender_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Loading

0 comments on commit a933764

Please sign in to comment.