Skip to content

Commit

Permalink
Implement indexed types for person properties and regions
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonasher committed May 21, 2024
1 parent 85acdbb commit 35e7085
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/data_containers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub trait Property: Any {
pub trait PropertyWithDefault: Any {
type Value: Any + Copy;
fn get_default() -> Self::Value;
fn index() -> usize;
}

impl<T: PropertyWithDefault> Property for T {
Expand Down
35 changes: 23 additions & 12 deletions src/data_containers/vector_heterogeneous_container.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::any::Any;

use crate::data_containers::PropertyWithDefault;

pub struct VecDataContainer {
data: HashMap<TypeId, Box<dyn Any>>,
data: Vec<Option<Box<dyn Any>>>,
}

impl Default for VecDataContainer {
Expand All @@ -15,16 +14,18 @@ impl Default for VecDataContainer {

impl VecDataContainer {
pub fn new() -> VecDataContainer {
VecDataContainer {
data: HashMap::new(),
}
VecDataContainer { data: Vec::new() }
}

pub fn set_value<K: PropertyWithDefault>(&mut self, index: usize, value: K::Value) {
let vec = self
.data
.entry(TypeId::of::<K>())
.or_insert_with(|| Box::new(Vec::<K::Value>::with_capacity(index)));
let property_index = K::index();
if property_index >= self.data.len() {
self.data.resize_with(property_index + 1, || None)
}
if self.data[property_index].is_none() {
self.data[property_index] = Some(Box::new(Vec::<K::Value>::with_capacity(index)));
}
let vec = self.data[property_index].as_mut().unwrap();
let vec: &mut Vec<K::Value> = vec.downcast_mut().unwrap();
if index >= vec.len() {
vec.resize(index + 1, K::get_default());
Expand All @@ -33,15 +34,17 @@ impl VecDataContainer {
}

pub fn get_value<K: PropertyWithDefault>(&self, index: usize) -> K::Value {
match self.data.get(&TypeId::of::<K>()) {
Some(boxed_vec) => {
let property_index = K::index();
match self.data.get(property_index) {
Some(Some(boxed_vec)) => {
let vec = &boxed_vec.downcast_ref::<Vec<K::Value>>().unwrap();
if index >= vec.len() {
K::get_default()
} else {
vec[index]
}
}
Some(&None) => unreachable!(),
None => K::get_default(),
}
}
Expand All @@ -58,6 +61,10 @@ mod tests {
fn get_default() -> <Self as PropertyWithDefault>::Value {
0
}

fn index() -> usize {
0
}
}

struct KeyTwo {}
Expand All @@ -67,6 +74,10 @@ mod tests {
fn get_default() -> <Self as PropertyWithDefault>::Value {
false
}

fn index() -> usize {
1
}
}

#[test]
Expand Down
33 changes: 33 additions & 0 deletions src/person_properties.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

use crate::context::Context;
use crate::data_containers::vector_heterogeneous_container::VecDataContainer;
Expand All @@ -10,6 +12,17 @@ use crate::people::{PersonBuilder, PersonId};

pub trait PersonProperty: PropertyWithDefault {}

static INDEX: Mutex<usize> = Mutex::new(0);

pub fn next(index: &AtomicUsize) -> usize {
let mut guard = INDEX.lock().unwrap();
if index.load(Ordering::SeqCst) == usize::MAX {
index.store(*guard, Ordering::SeqCst);
*guard += 1;
}
index.load(Ordering::Relaxed)
}

#[macro_export]
macro_rules! define_person_property {
($person_property:ident, $value:ty, $default: expr) => {
Expand All @@ -21,6 +34,16 @@ macro_rules! define_person_property {
fn get_default() -> Self::Value {
$default
}

fn index() -> usize {
static INDEX: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(usize::MAX);
let mut index = INDEX.load(std::sync::atomic::Ordering::Relaxed);
if index == usize::MAX {
index = $crate::person_properties::next(&INDEX);
}
index
}
}

impl $crate::person_properties::PersonProperty for $person_property {}
Expand All @@ -37,6 +60,16 @@ macro_rules! define_person_property_from_enum {
fn get_default() -> Self::Value {
$default
}

fn index() -> usize {
static INDEX: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(usize::MAX);
let mut index = INDEX.load(std::sync::atomic::Ordering::Relaxed);
if index == usize::MAX {
index = $crate::context::next(&INDEX);
}
index
}
}

impl $crate::person_properties::PersonProperty for $person_property {}
Expand Down
23 changes: 23 additions & 0 deletions src/regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::people::{PersonBuilder, PersonId};
use std::any::TypeId;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex;

#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Debug)]
pub struct RegionId {
Expand All @@ -21,6 +23,17 @@ impl RegionId {

pub trait RegionProperty: PropertyWithDefault {}

static INDEX: Mutex<usize> = Mutex::new(0);

pub fn next(index: &AtomicUsize) -> usize {
let mut guard = INDEX.lock().unwrap();
if index.load(Ordering::SeqCst) == usize::MAX {
index.store(*guard, Ordering::SeqCst);
*guard += 1;
}
index.load(Ordering::Relaxed)
}

#[macro_export]
macro_rules! define_region_property {
($region_property:ident, $value:ty, $default: expr) => {
Expand All @@ -32,6 +45,16 @@ macro_rules! define_region_property {
fn get_default() -> Self::Value {
$default
}

fn index() -> usize {
static INDEX: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(usize::MAX);
let mut index = INDEX.load(std::sync::atomic::Ordering::Relaxed);
if index == usize::MAX {
index = $crate::regions::next(&INDEX);
}
index
}
}

impl $crate::regions::RegionProperty for $region_property {}
Expand Down

0 comments on commit 35e7085

Please sign in to comment.