Skip to content

Commit 1c9e17a

Browse files
committed
Add TickIndexBitmap
1 parent 548cf7b commit 1c9e17a

File tree

2 files changed

+231
-101
lines changed

2 files changed

+231
-101
lines changed

pallets/swap/src/lib.rs

+65-97
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use safe_math::*;
99
use sp_arithmetic::helpers_128bit::sqrt;
1010
use substrate_fixed::types::U64F64;
1111

12-
use self::tick::{Tick, TickIndex};
12+
use self::tick::{Tick, TickIndex, TickIndexBitmap};
1313

1414
pub mod pallet;
1515
mod tick;
@@ -1115,46 +1115,34 @@ where
11151115
/// Deletion: 2 reads, 1-3 writes
11161116
///
11171117
1118-
// Addresses an index as (word, bit)
1119-
fn index_to_address(index: u32) -> (u32, u32) {
1120-
let word: u32 = index.safe_div(128);
1121-
let bit: u32 = index.checked_rem(128).unwrap_or_default();
1122-
(word, bit)
1123-
}
1124-
1125-
// Reconstructs an index from address in lower level
1126-
fn address_to_index(word: u32, bit: u32) -> u32 {
1127-
word.saturating_mul(128).saturating_add(bit)
1128-
}
1118+
// Use TickIndexBitmap::layer_to_index instead
11291119

11301120
pub fn insert_active_tick(&mut self, index: TickIndex) {
11311121
// Check the range
11321122
if (index < TickIndex::MIN) || (index > TickIndex::MAX) {
11331123
return;
11341124
}
11351125

1136-
// Convert the tick index value to an offset_index for the tree representation
1137-
// to avoid working with the sign bit.
1138-
let offset_index = (index.get() + TickIndex::OFFSET.get()) as u32;
1139-
1140-
// Calculate index in each layer
1141-
let (layer2_word, layer2_bit) = Self::index_to_address(offset_index);
1142-
let (layer1_word, layer1_bit) = Self::index_to_address(layer2_word);
1143-
let (layer0_word, layer0_bit) = Self::index_to_address(layer1_word);
1126+
// Convert to bitmap representation
1127+
let bitmap = TickIndexBitmap::from(index);
11441128

11451129
// Update layer words
1146-
let mut word0_value = self.state_ops.get_layer0_word(layer0_word);
1147-
let mut word1_value = self.state_ops.get_layer1_word(layer1_word);
1148-
let mut word2_value = self.state_ops.get_layer2_word(layer2_word);
1149-
1150-
let bit: u128 = 1;
1151-
word0_value = word0_value | bit.wrapping_shl(layer0_bit);
1152-
word1_value = word1_value | bit.wrapping_shl(layer1_bit);
1153-
word2_value = word2_value | bit.wrapping_shl(layer2_bit);
1154-
1155-
self.state_ops.set_layer0_word(layer0_word, word0_value);
1156-
self.state_ops.set_layer1_word(layer1_word, word1_value);
1157-
self.state_ops.set_layer2_word(layer2_word, word2_value);
1130+
let mut word0_value = self.state_ops.get_layer0_word(bitmap.word_at(0));
1131+
let mut word1_value = self.state_ops.get_layer1_word(bitmap.word_at(1));
1132+
let mut word2_value = self.state_ops.get_layer2_word(bitmap.word_at(2));
1133+
1134+
// Set bits in each layer
1135+
word0_value |= bitmap.bit_mask(0);
1136+
word1_value |= bitmap.bit_mask(1);
1137+
word2_value |= bitmap.bit_mask(2);
1138+
1139+
// Update the storage
1140+
self.state_ops
1141+
.set_layer0_word(bitmap.word_at(0), word0_value);
1142+
self.state_ops
1143+
.set_layer1_word(bitmap.word_at(1), word1_value);
1144+
self.state_ops
1145+
.set_layer2_word(bitmap.word_at(2), word2_value);
11581146
}
11591147

11601148
pub fn remove_active_tick(&mut self, index: TickIndex) {
@@ -1163,58 +1151,30 @@ where
11631151
return;
11641152
}
11651153

1166-
// Convert the tick index value to an offset_index for the tree representation
1167-
// to avoid working with the sign bit.
1168-
let offset_index = (index.get() + TickIndex::OFFSET.get()) as u32;
1169-
1170-
// Calculate index in each layer
1171-
let (layer2_word, layer2_bit) = Self::index_to_address(offset_index);
1172-
let (layer1_word, layer1_bit) = Self::index_to_address(layer2_word);
1173-
let (layer0_word, layer0_bit) = Self::index_to_address(layer1_word);
1154+
// Convert to bitmap representation
1155+
let bitmap = TickIndexBitmap::from(index);
11741156

11751157
// Update layer words
1176-
let mut word0_value = self.state_ops.get_layer0_word(layer0_word);
1177-
let mut word1_value = self.state_ops.get_layer1_word(layer1_word);
1178-
let mut word2_value = self.state_ops.get_layer2_word(layer2_word);
1158+
let mut word0_value = self.state_ops.get_layer0_word(bitmap.word_at(0));
1159+
let mut word1_value = self.state_ops.get_layer1_word(bitmap.word_at(1));
1160+
let mut word2_value = self.state_ops.get_layer2_word(bitmap.word_at(2));
11791161

11801162
// Turn the bit off (& !bit) and save as needed
1181-
let bit: u128 = 1;
1182-
word2_value = word2_value & !bit.wrapping_shl(layer2_bit);
1183-
self.state_ops.set_layer2_word(layer2_word, word2_value);
1163+
word2_value &= !bitmap.bit_mask(2);
1164+
self.state_ops
1165+
.set_layer2_word(bitmap.word_at(2), word2_value);
1166+
11841167
if word2_value == 0 {
1185-
word1_value = word1_value & !bit.wrapping_shl(layer1_bit);
1186-
self.state_ops.set_layer1_word(layer1_word, word1_value);
1187-
}
1188-
if word1_value == 0 {
1189-
word0_value = word0_value & !bit.wrapping_shl(layer0_bit);
1190-
self.state_ops.set_layer0_word(layer0_word, word0_value);
1168+
word1_value &= !bitmap.bit_mask(1);
1169+
self.state_ops
1170+
.set_layer1_word(bitmap.word_at(1), word1_value);
11911171
}
1192-
}
11931172

1194-
// Finds the closest active bit and, if active bit exactly matches bit, then the next one
1195-
// Exact match: return Some([next, bit])
1196-
// Non-exact match: return Some([next])
1197-
// No match: return None
1198-
fn find_closest_active_bit_candidates(&self, word: u128, bit: u32, lower: bool) -> Vec<u32> {
1199-
let mut result = vec![];
1200-
let mut mask: u128 = 1_u128.wrapping_shl(bit);
1201-
let mut layer0_active_bit: u32 = bit;
1202-
while mask > 0 {
1203-
if mask & word != 0 {
1204-
result.push(layer0_active_bit);
1205-
if layer0_active_bit != bit {
1206-
break;
1207-
}
1208-
}
1209-
mask = if lower {
1210-
layer0_active_bit = layer0_active_bit.saturating_sub(1);
1211-
mask.wrapping_shr(1)
1212-
} else {
1213-
layer0_active_bit = layer0_active_bit.saturating_add(1);
1214-
mask.wrapping_shl(1)
1215-
};
1173+
if word1_value == 0 {
1174+
word0_value &= !bitmap.bit_mask(0);
1175+
self.state_ops
1176+
.set_layer0_word(bitmap.word_at(0), word0_value);
12161177
}
1217-
result
12181178
}
12191179

12201180
pub fn find_closest_active_tick_index(
@@ -1227,28 +1187,31 @@ where
12271187
return None;
12281188
}
12291189

1230-
// Convert the tick index value to an offset_index for the tree representation
1231-
// to avoid working with the sign bit.
1232-
let offset_index = (index.get() + TickIndex::OFFSET.get()) as u32;
1190+
// Convert to bitmap representation
1191+
let bitmap = TickIndexBitmap::from(index);
12331192
let mut found = false;
12341193
let mut result: u32 = 0;
12351194

1236-
// Calculate index in each layer
1237-
let (layer2_word, layer2_bit) = Self::index_to_address(offset_index);
1238-
let (layer1_word, layer1_bit) = Self::index_to_address(layer2_word);
1239-
let (layer0_word, layer0_bit) = Self::index_to_address(layer1_word);
1195+
// Layer positions from bitmap
1196+
let layer0_word = bitmap.word_at(0);
1197+
let layer0_bit = bitmap.bit_at(0);
1198+
let layer1_word = bitmap.word_at(1);
1199+
let layer1_bit = bitmap.bit_at(1);
1200+
let layer2_word = bitmap.word_at(2);
1201+
let layer2_bit = bitmap.bit_at(2);
12401202

12411203
// Find the closest active bits in layer 0, then 1, then 2
12421204

12431205
///////////////
12441206
// Level 0
12451207
let word0 = self.state_ops.get_layer0_word(layer0_word);
1246-
let closest_bits_l0 = self.find_closest_active_bit_candidates(word0, layer0_bit, lower);
1208+
let closest_bits_l0 =
1209+
TickIndexBitmap::find_closest_active_bit_candidates(word0, layer0_bit, lower);
12471210

12481211
closest_bits_l0.iter().for_each(|&closest_bit_l0| {
12491212
///////////////
12501213
// Level 1
1251-
let word1_index = Self::address_to_index(0, closest_bit_l0);
1214+
let word1_index = TickIndexBitmap::layer_to_index(0, closest_bit_l0);
12521215

12531216
// Layer 1 words are different, shift the bit to the word edge
12541217
let start_from_l1_bit = if word1_index < layer1_word {
@@ -1260,12 +1223,15 @@ where
12601223
};
12611224
let word1_value = self.state_ops.get_layer1_word(word1_index);
12621225

1263-
let closest_bits_l1 =
1264-
self.find_closest_active_bit_candidates(word1_value, start_from_l1_bit, lower);
1226+
let closest_bits_l1 = TickIndexBitmap::find_closest_active_bit_candidates(
1227+
word1_value,
1228+
start_from_l1_bit,
1229+
lower,
1230+
);
12651231
closest_bits_l1.iter().for_each(|&closest_bit_l1| {
12661232
///////////////
12671233
// Level 2
1268-
let word2_index = Self::address_to_index(word1_index, closest_bit_l1);
1234+
let word2_index = TickIndexBitmap::layer_to_index(word1_index, closest_bit_l1);
12691235

12701236
// Layer 2 words are different, shift the bit to the word edge
12711237
let start_from_l2_bit = if word2_index < layer2_word {
@@ -1277,13 +1243,16 @@ where
12771243
};
12781244

12791245
let word2_value = self.state_ops.get_layer2_word(word2_index);
1280-
let closest_bits_l2 =
1281-
self.find_closest_active_bit_candidates(word2_value, start_from_l2_bit, lower);
1246+
let closest_bits_l2 = TickIndexBitmap::find_closest_active_bit_candidates(
1247+
word2_value,
1248+
start_from_l2_bit,
1249+
lower,
1250+
);
12821251

12831252
if closest_bits_l2.len() > 0 {
12841253
// The active tick is found, restore its full index and return
12851254
let offset_found_index =
1286-
Self::address_to_index(word2_index, closest_bits_l2[0]);
1255+
TickIndexBitmap::layer_to_index(word2_index, closest_bits_l2[0]);
12871256

12881257
if lower {
12891258
if (offset_found_index > result) || (!found) {
@@ -1300,13 +1269,12 @@ where
13001269
});
13011270
});
13021271

1303-
if found {
1304-
// Convert the tree offset_index back to a tick index value
1305-
let tick_value = (result as i32).saturating_sub(TickIndex::OFFSET.get());
1306-
Some(TickIndex::new_unchecked(tick_value))
1307-
} else {
1308-
None
1272+
if !found {
1273+
return None;
13091274
}
1275+
1276+
// Convert the result offset_index back to a tick index
1277+
TickIndex::from_offset_index(result).ok()
13101278
}
13111279

13121280
pub fn find_closest_lower_active_tick_index(&self, index: TickIndex) -> Option<TickIndex> {

0 commit comments

Comments
 (0)