Inefficient get_unused_index
implementation
The PositionData::get_unused_index
method iterates up to 100 times looking for an available PositionData
slot in the positions
array. This is because closed positions are marked by taking the specified PositionData
and setting that entry to None
.
If, instead, this was implemented by tracking the next available index (_we'll refer to this as next_index
_) used to fill a position and swapping the last position with the newly closed position, there would never be gaps in the positions. This means that get_unused_index
can just return next_index
after ensuring that next_index
is not out of bounds (less than 100
).
An example updated PositionData
that would use this fast implementation for get_unused_index
could look like the following:
pub struct PositionData {
pub owner: Pubkey,
pub positions: [Option<Position>; MAX_POSITIONS],
next_index: usize
}
impl PositionData {
/// Finds first index available for a new position
pub fn get_unused_index(&self) -> Result<usize> {
if self.next_index < MAX_POSITIONS {
Ok(next_index)
} else {
Err(error!(ErrorCode::TooManyPositions))
}
}
pub fn add_position(&mut self, position: Position) -> Result<()> {
let index = self.get_unused_index()?;
self.positions[index] = Some(position);
self.next_index += 1;
Ok(())
}
pub fn delete_position(&mut self, position_index: usize) -> Result<()> {
if position_index >= MAX_POSITIONS {
return Err(error!(ErrorCode::PositionNotInUse));
}
match self.positions[position_index] {
Some(_) => {
self.next_index -= 1;
self.positions[position_index] = self.positions[self.next_index];
self.positions[self.next_index] = None;
Ok(())
},
None => Err(error!(ErrorCode::PositionNotInUse))
}
}
}