Skip to content

Commit

Permalink
feat: TickBitmap
Browse files Browse the repository at this point in the history
  • Loading branch information
detectivekim committed Jun 20, 2024
1 parent 65224a1 commit c09e929
Show file tree
Hide file tree
Showing 3 changed files with 384 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub mod libraries {
pub mod order_id;
pub mod packed_u256;
pub mod tick;
pub mod tick_bitmap;
pub mod significant_bit;
}

pub mod utils {
Expand Down
275 changes: 275 additions & 0 deletions src/libraries/significant_bit.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
// http://supertech.csail.mit.edu/papers/debruijn.pdf
const DEBRUIJN_SEQ: u256 = 0x818283848586878898A8B8C8D8E8F929395969799A9B9D9E9FAAEB6BEDEEFF;
const DEBRUIJN_INDEX: [
u8
; 256] = [
0,
1,
2,
9,
3,
17,
10,
25,
4,
33,
18,
41,
11,
49,
26,
57,
5,
65,
34,
69,
19,
77,
42,
85,
12,
93,
50,
101,
27,
109,
58,
117,
6,
38,
66,
98,
35,
125,
70,
133,
20,
128,
78,
141,
43,
149,
86,
157,
13,
73,
94,
165,
51,
169,
102,
177,
28,
136,
110,
185,
59,
193,
118,
201,
7,
23,
39,
55,
67,
83,
99,
115,
36,
131,
126,
155,
71,
175,
134,
199,
21,
81,
129,
173,
79,
209,
142,
211,
44,
144,
150,
219,
87,
213,
158,
227,
14,
46,
74,
106,
95,
146,
166,
190,
52,
152,
170,
224,
103,
221,
178,
235,
29,
89,
137,
181,
111,
215,
186,
243,
60,
160,
194,
238,
119,
229,
202,
247,
255,
8,
16,
24,
32,
40,
48,
56,
64,
68,
76,
84,
92,
100,
108,
116,
37,
97,
124,
132,
127,
140,
148,
156,
72,
164,
168,
176,
135,
184,
192,
200,
22,
54,
82,
114,
130,
154,
174,
198,
80,
172,
208,
210,
143,
218,
212,
226,
45,
105,
145,
189,
151,
223,
220,
234,
88,
180,
214,
242,
159,
237,
228,
246,
254,
15,
31,
47,
63,
75,
91,
107,
96,
123,
139,
147,
163,
167,
183,
191,
53,
113,
153,
197,
171,
207,
217,
225,
104,
188,
222,
233,
179,
241,
236,
245,
253,
30,
62,
90,
122,
138,
162,
182,
112,
196,
206,
216,
187,
232,
240,
244,
252,
61,
121,
161,
195,
205,
231,
239,
251,
120,
204,
230,
250,
203,
249,
248
];

#[generate_trait]
pub impl SignificantBitImpl of SignificantBitTrait {
fn least_significant_bit(x: u256) -> u8 {
assert!(x != 0, "x must be non-zero");
let index = (x & (~x + 1))
* DEBRUIJN_SEQ
/ 0x100000000000000000000000000000000000000000000000000000000000000;
return 1;
// let arr = DEBRUIJN_INDEX.span();
// arr[index]
}
}
107 changes: 107 additions & 0 deletions src/libraries/tick_bitmap.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use core::dict::Felt252DictTrait;
use core::traits::Into;
use clober_cairo::libraries::tick::Tick;
use alexandria_math::fast_power::fast_power;
use clober_cairo::libraries::significant_bit::{SignificantBitImpl};

const TWO_POW_128: u256 = 0x100000000000000000000000000000000; // 2**128
const B0_BITMAP_KEY: felt252 = 0x15654;

#[derive(Destruct)]
pub struct TickBitmap {
pub hi: Felt252Dict<u128>,
pub low: Felt252Dict<u128>,
}

fn _split(tick: Tick) -> (u32, u32) {
let mut value: u32 = ~(tick.value + 0x800000).try_into().unwrap();
value = ~value + 0x800000;
let b0b1 = (value & 0xffff00) / 256;
let b2 = value & 0xff;
(b0b1, b2)
}

fn _to_tick(raw: felt252) -> Tick {
let value: u32 = (~(raw - 0x800000).try_into().unwrap()) & 0xffffff;
let value: i32 = value.try_into().unwrap();
Tick { value }
}

fn _get(ref bitmap: TickBitmap, key: felt252) -> u256 {
bitmap.hi.get(key).into() * TWO_POW_128 + bitmap.low.get(key).into()
}

fn _set(ref bitmap: TickBitmap, key: felt252, value: u256) {
bitmap.hi.insert(key, (value / TWO_POW_128).try_into().unwrap());
bitmap.low.insert(key, (value % TWO_POW_128).try_into().unwrap());
}

fn _is_empty(ref bitmap: TickBitmap) -> bool {
_get(ref bitmap, B0_BITMAP_KEY) == 0
}

#[generate_trait]
impl TickBitmapImpl of TickBitmapTrait {
fn has(ref bitmap: TickBitmap, tick: Tick) -> bool {
let (b0b1, b2) = _split(tick);
let mask: u256 = fast_power(2, (b2)).into();
let value = _get(ref bitmap, b0b1.into());
value & mask == mask
}

fn is_empty(ref bitmap: TickBitmap) -> bool {
_get(ref bitmap, B0_BITMAP_KEY) == 0
}

fn highest(ref bitmap: TickBitmap) -> Tick {
assert(_is_empty(ref bitmap), 'EmptyError');

let b0: u32 = SignificantBitImpl::least_significant_bit(_get(ref bitmap, B0_BITMAP_KEY))
.into();
let b0b1: u32 = (b0 * 256)
| SignificantBitImpl::least_significant_bit(_get(ref bitmap, (~b0).into())).into();
let b2: u32 = SignificantBitImpl::least_significant_bit(_get(ref bitmap, b0b1.into()))
.into();
_to_tick(((b0b1 * 256) + b2).into())
}

fn set(ref bitmap: TickBitmap, tick: Tick) {
let (b0b1, b2) = _split(tick);
let mut mask: u256 = fast_power(2, (b2)).into();
let mut b2Bitmap = _get(ref bitmap, b0b1.into());
assert(b2Bitmap & mask == 0, 'AlreadyExistsError');

_set(ref bitmap, b0b1.into(), b2Bitmap | mask);
if b2Bitmap == 0 {
mask = fast_power(2, (b0b1 & 0xff)).into();
let b1BitmapKey = ~(b0b1 / 256);
let mut b1Bitmap = _get(ref bitmap, b1BitmapKey.into());
_set(ref bitmap, b1BitmapKey.into(), b1Bitmap | mask);
if b1Bitmap == 0 {
_set(
ref bitmap,
B0_BITMAP_KEY,
_get(ref bitmap, B0_BITMAP_KEY) | fast_power(2, (~b1BitmapKey)).into()
);
}
}
}

fn clear(ref bitmap: TickBitmap, tick: Tick) {
let (b0b1, b2) = _split(tick);
let mut mask: u256 = fast_power(2, (b2)).into();
let mut b2Bitmap = _get(ref bitmap, b0b1.into());
_set(ref bitmap, b0b1.into(), b2Bitmap & (~mask));
if b2Bitmap == mask {
mask = fast_power(2, (b0b1 & 0xff)).into();
let b1BitmapKey = ~(b0b1 / 256);
let mut b1Bitmap = _get(ref bitmap, b1BitmapKey.into());
_set(ref bitmap, b1BitmapKey.into(), b1Bitmap & (~mask));
if mask == b1Bitmap {
mask = fast_power(2, (~b1BitmapKey)).into();
_set(ref bitmap, B0_BITMAP_KEY, _get(ref bitmap, B0_BITMAP_KEY) & (~mask));
}
}
}
}

0 comments on commit c09e929

Please sign in to comment.