From ea96a0eb0ddaa6458e1a3099bf20bcca48e72db7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20K=C3=A4nner?= Date: Tue, 21 Jan 2025 20:25:54 +0100 Subject: [PATCH] put small field bitfields on the stack --- battlesnake/src/types/simulation.rs | 65 +++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 7 deletions(-) diff --git a/battlesnake/src/types/simulation.rs b/battlesnake/src/types/simulation.rs index 2ab807d..0756efb 100644 --- a/battlesnake/src/types/simulation.rs +++ b/battlesnake/src/types/simulation.rs @@ -1,4 +1,9 @@ -use std::{collections::VecDeque, fmt::Display}; +use std::{ + collections::VecDeque, + fmt::Display, + num::NonZeroUsize, + ops::{Deref, DerefMut}, +}; use bitvec::prelude::*; use log::{error, warn}; @@ -6,6 +11,52 @@ use rand::prelude::*; use super::{wire::Request, Coord, Direction}; +#[derive(Debug, PartialEq, Eq, Clone)] +enum SmallBitBox { + Stack { + storage: BitArr!(for Self::STACK_BITS), + len: NonZeroUsize, + }, + Heap(BitBox), +} + +impl SmallBitBox { + const STACK_BITS: usize = usize::BITS as usize * 3; + + fn new(initial: bool, len: usize) -> Self { + if let len @ 1..Self::STACK_BITS = len { + let Some(len) = NonZeroUsize::new(len) else { + unreachable!() + }; + let mut storage = BitArray::ZERO; + storage.fill(initial); + Self::Stack { storage, len } + } else { + Self::Heap(bitbox![u8::from(initial); len]) + } + } +} + +impl Deref for SmallBitBox { + type Target = BitSlice; + + fn deref(&self) -> &Self::Target { + match self { + Self::Stack { storage, len } => &storage[..len.get()], + Self::Heap(bit_box) => bit_box, + } + } +} + +impl DerefMut for SmallBitBox { + fn deref_mut(&mut self) -> &mut Self::Target { + match self { + Self::Stack { storage, len } => &mut storage[..len.get()], + Self::Heap(bit_box) => bit_box, + } + } +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct Board { width: u8, @@ -14,9 +65,9 @@ pub struct Board { food_spawn_chance: u8, min_food: u16, turn: u32, - food: BitBox, - hazard: BitBox, - free: BitBox, + food: SmallBitBox, + hazard: SmallBitBox, + free: SmallBitBox, snakes: Vec, constrictor: bool, } @@ -33,9 +84,9 @@ impl From<&Request> for Board { food_spawn_chance: value.game.ruleset.settings.food_spawn_chance, min_food: value.game.ruleset.settings.minimum_food, turn: value.turn, - food: bitbox![0; fields], - hazard: bitbox![0; fields], - free: bitbox![1; fields], + food: SmallBitBox::new(false, fields), + hazard: SmallBitBox::new(false, fields), + free: SmallBitBox::new(true, fields), snakes: Vec::with_capacity(value.board.snakes.len()), constrictor: value.game.ruleset.name == "constrictor", };