Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #![allow(dead_code)]
- #![allow(unused_imports)]
- mod util {
- /// Trait Newable are all objects that have a new method
- pub trait Newable {
- fn new() -> Self;
- }
- /// Trait Parseable are all objects that have a parse method (string to object)
- pub trait Parseable {
- fn parse(_: &str) -> Self;
- }
- /// Trait Encodeable are all objects that have an encode method (object to string)
- pub trait Encodeable {
- fn encode(&self) -> String;
- }
- /// Trait Equalable are all objects that can be compared to themselves
- pub trait Equalable {
- fn equals(&self, _: &Self) -> bool;
- }
- /// Trait Hashable are all objects that a hash can be extracted from (a hash is a unique identifier for the object)
- pub trait Hashable {
- fn hash(&self) -> usize;
- }
- /// `debug_passed` is a macro that takes an input (preferably a string) as the checkpoint name and prints "passed checkpoint <name> in file <file> line <line>"
- #[macro_export]
- macro_rules! debug_passed {
- ($x:expr) => {
- #[cfg(debug_assertions)]
- {
- println!(
- "Program execution passed checkpoint <{}>, in file <{}> line <{}>",
- $x,
- file!(),
- line!()
- )
- }
- };
- }
- /// `debug_val` is a macro that prints out a value (for debugging purposes)
- #[macro_export]
- macro_rules! debug_val {
- ($val:expr) => {
- #[cfg(debug_assertions)]
- {
- match $val {
- tmp => {
- println!(
- "<{}> <{}> {} = {:#?}",
- file!(),
- line!(),
- stringify!($val),
- &tmp
- );
- tmp
- }
- }
- }
- };
- }
- /// `debug_emit` is a macro that prints to stderr
- #[macro_export]
- macro_rules! debug_emit {
- ($val:expr) => {
- #[cfg(debug_assertions)]
- {
- println!("<{}> <{}>, {}", file!(), line!(), $val)
- };
- };
- }
- /// `TwoTuple` is a 2 element tuple
- #[derive(Clone, Copy, Debug)]
- pub struct TwoTuple<DataTypeA: Clone, DataTypeB: Clone> {
- a: DataTypeA,
- b: DataTypeB,
- }
- impl<DataTypeA: Clone, DataTypeB: Clone> TwoTuple<DataTypeA, DataTypeB> {
- pub fn new(input1: DataTypeA, input2: DataTypeB) -> TwoTuple<DataTypeA, DataTypeB> {
- TwoTuple {
- a: input1,
- b: input2,
- }
- }
- pub fn car(&self) -> DataTypeA {
- self.a.clone()
- }
- pub fn cdr(&self) -> DataTypeB {
- self.b.clone()
- }
- }
- /// `UsizeWrapper` is a wrapper for usize satisfying various traits
- #[derive(Clone, Debug, PartialEq)]
- pub struct UsizeWrapper {
- data: usize,
- }
- /// `StringWrapper` is a wrapper for string satisfying various traits
- #[derive(Clone, Debug, PartialEq)]
- pub struct StringWrapper {
- data: String,
- }
- impl UsizeWrapper {
- pub fn from(data_1: usize) -> Self {
- UsizeWrapper { data: data_1 }
- }
- pub fn get_data(&self) -> usize {
- self.data
- }
- }
- impl Newable for UsizeWrapper {
- fn new() -> Self {
- UsizeWrapper { data: 0 }
- }
- }
- impl Parseable for UsizeWrapper {
- fn parse(data: &str) -> Self {
- UsizeWrapper {
- data: data.parse::<usize>().unwrap(),
- }
- }
- }
- impl Encodeable for UsizeWrapper {
- fn encode(&self) -> String {
- self.data.to_string()
- }
- }
- impl Newable for StringWrapper {
- fn new() -> Self {
- StringWrapper {
- data: String::new(),
- }
- }
- }
- impl Parseable for StringWrapper {
- fn parse(data: &str) -> Self {
- StringWrapper {
- data: data.parse::<String>().unwrap(),
- }
- }
- }
- impl Encodeable for StringWrapper {
- fn encode(&self) -> String {
- self.data.clone()
- }
- }
- /// Function `parse_csv_list` parses a comma seperated list
- pub fn parse_csv_list<DataType: Parseable + Clone>(input: &str, character: char) -> Vec<DataType> {
- let mut to_return: Vec<DataType> = Vec::new();
- for elem in input.split(character) {
- to_return.push(Parseable::parse(elem));
- }
- to_return
- }
- pub fn parse_csv_list_native<DataType: std::str::FromStr>(
- input: &str,
- character: char,
- ) -> Vec<DataType> {
- let mut to_return: Vec<DataType> = Vec::new();
- for elem in input.split(character) {
- to_return.push(if let Ok(a) = elem.parse::<DataType>() {
- a
- } else {
- panic!("Invalid token found");
- });
- }
- to_return
- }
- /// Function `parse_list` parses a list
- pub fn parse_list_multi<DataType: Parseable + Clone>(
- input: &str,
- vocab: &str,
- level: usize,
- ) -> Vec<DataType> {
- if level >= vocab.len() {
- panic!("Out of tokens");
- }
- let token = {
- if let Some(a) = vocab.chars().nth(level) {
- a
- } else {
- panic!("Out of tokens");
- }
- };
- let mut to_return: Vec<DataType> = Vec::new();
- for elem in input.split(token) {
- to_return.push(Parseable::parse(elem));
- }
- to_return
- }
- /// Function `parse_table` parses a table and returns the sections
- pub fn parse_table_sections(input: &str) -> Vec<String> {
- let the_string = input.to_string();
- let fst = {
- if let Some(a) = the_string.split(';').nth(0) {
- a
- } else {
- panic!("Symbol table is invalid");
- }
- };
- let header_len = {
- if let Ok(a) = fst.to_string().parse::<usize>() {
- a
- } else {
- panic!("Header length is not an integer");
- }
- };
- let header_start = fst.chars().count() + 1;
- let header_end = header_start + header_len;
- let body_start = header_end + 1;
- let body_end = the_string.chars().count();
- let header = (&the_string[header_start..header_end]).to_string();
- let body = (&the_string[body_start..body_end]).to_string();
- if the_string.chars().collect::<Vec<char>>()[body_start - 1] != ';' {
- panic!("Symbol table is invalid");
- }
- let tokenized_header = {
- let mut to_return: Vec<usize> = Vec::new();
- let tmp = header.split(',').collect::<Vec<&str>>();
- for item in tmp {
- if let Ok(a) = item.to_string().parse::<usize>() {
- to_return.push(a);
- } else {
- panic!("Symbol table is invalid");
- }
- }
- to_return
- };
- let mut to_return: Vec<String> = Vec::new();
- let mut old_offset = 0;
- for item in tokenized_header {
- to_return.push((&body[(old_offset)..(old_offset + item)]).to_string());
- old_offset += item;
- }
- to_return
- }
- pub fn access_flattened_vec<'a, T>(
- list: &'a [T],
- coords: &[isize],
- dimensions: &[usize],
- offset: usize,
- ) -> &'a T {
- eprintln!("Entering function access_flattened_Vec");
- if coords.len() != dimensions.len() {
- panic!("Dimensions do not match");
- }
- let mut old_len = list.len();
- let sizes = dimensions
- .iter()
- .map(|&x| {
- old_len /= x;
- old_len
- })
- .collect::<Vec<usize>>();
- let mut addr: usize = 0;
- for j in 0..sizes.len() {
- addr += (coords[j] * (sizes[j] as isize)) as usize;
- }
- addr += offset;
- &list[addr]
- }
- }
- use std::marker::PhantomData;
- use std::str::FromStr;
- use std::cell::Cell;
- use std::cell::Ref;
- use std::cell::RefCell;
- use std::cell::RefMut;
- /// Trait `GridMeta` is the trait that all metadata for a Grid must satisfy
- pub trait GridMeta {
- fn get_dimensions(&self) -> &[usize];
- }
- #[derive(Clone)]
- /// `GridDataType` is the datatype of the data inside of a grid (the struct Grid is just a wrapper around `GridDataType` with a few more functions)
- pub struct GridDataType<CellDataType> {
- /// Data is just the data of the grid. The data is "flattened" to 1 dimension, no matter how many dimensions the grid is
- pub data: Vec<CellDataType>,
- /// Dimensions is a vector that stores the dimensions of the data - for example, a 2x2 grid (a 2d grid, with 2 rows and 2 columns) would be [2, 2]. The convention is that the size of x is before the size of y before the size of z etc, so a 3d grid with length (x size) 3, width (y size) 4 and height (z size) 5 would be [3,4,5]
- pub dimensions: Vec<usize>,
- }
- #[derive(Clone)]
- /// `NeighborType` is the datatype for the neighborhood of a cell
- pub struct NeighborType<'a, CellDataType> {
- /// Data contains the neighborhood
- pub data: Vec<&'a CellDataType>,
- /// Dimensions is the dimensions
- pub dimensions: &'a [usize],
- }
- /// `TransitionFunc` is the transition function (AKA "rule") of the cellular automata
- pub type TransitionFunc<CellDataType, MetaDataType /*: util::Newable*/> =
- dyn Fn(&mut CellDataType, &NeighborType<CellDataType>, &MetaDataType) -> ();
- /// `NeighborFuncParser` is the function that returns the neighborhood of a cell
- pub type NeighborFuncParser<CellDataType, MetaDataType /*: util::Newable*/> =
- dyn for<'a, 'b> Fn(
- &'b Ref<'b, GridDataType<CellDataType>>,
- &'a MetaDataType,
- usize,
- ) -> NeighborType<'b, CellDataType>;
- /*
- pub type NeighborFuncParser<'a, CellDataType, MetaDataType: util::Newable> =
- Fn(&'a GridDataType<CellDataType>, &MetaDataType, usize) -> NeighborType<'a, CellDataType>;
- */
- /// `DynamicExecArgs` are the arguments passed to an `ExecFunc` (see `ExecFunc`) that change based on the call
- pub struct DynamicExecArgs<'a, CellDataType> {
- low: usize,
- high: usize,
- to_write: &'a mut [CellDataType],
- }
- pub struct StaticExecArgs<'a, CellDataType, MetaDataType> {
- transition: &'a TransitionFunc<CellDataType, MetaDataType>,
- neighbor_parser: &'a NeighborFuncParser<CellDataType, MetaDataType>,
- to_read: Ref<'a, GridDataType<CellDataType>>,
- meta: &'a MetaDataType,
- }
- /// `ExecFunc` is an internal function that does the computation for a "chunk" of data - each chunk is done in parallel.
- pub type ExecFunc<CellDataType, MetaDataType /*: util::Newable*/> = Fn(
- &StaticExecArgs<'_, CellDataType, MetaDataType>,
- &mut DynamicExecArgs<'_, CellDataType>,
- ) -> ();
- /// `RunFunc` is the function that runs a function (of type `ExecFunc`) on a seperate thread (or, if there are no threads, simply runs the function)
- pub type RunFunc<CellDataType, MetaDataType /*: util::Newable*/> = Fn(
- &ExecFunc<CellDataType, MetaDataType>,
- &StaticExecArgs<'_, CellDataType, MetaDataType>,
- &mut DynamicExecArgs<'_, CellDataType>,
- ) -> ();
- /// `HaltFunc` is the function that tells the program whether to halt or not (true = halt, false = not halt, obviously)
- pub type HaltFunc<CellType> = Fn(&GridDataType<CellType>) -> bool;
- /// Grid is the datatype for a Grid object, where all of the cells are stored
- #[derive(Clone)]
- pub struct Grid<
- CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable,
- MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
- > {
- /// Direction determines which data (data_a or data_b) will be read from, and which data will be written to (the data being read from is never the data being written to). Direction "flops" each cycle. True = write to (modify) data_a, read from data_b (so data_a is ALWAYS the most recent one), false = other way around.
- direction: Cell<bool>,
- /// Data_a contains the vector. Depending on direction, it is either read to or written to.
- data_a: RefCell<GridDataType<CellDataType>>,
- /// Data_a contains the vector. Depending on direction, it is either read to or written to.
- data_b: RefCell<GridDataType<CellDataType>>,
- /// Metadata is the metadata for the grid (for example, for a grid with a modular cell type (e.g. all integers less than 5), the modulus would be metadata)
- meta: MetaDataType,
- }
- impl<
- CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable,
- MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
- > Default for Grid<CellDataType, MetaDataType>
- {
- fn default() -> Self {
- Self::new()
- }
- }
- impl<
- CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable,
- MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
- > Grid<CellDataType, MetaDataType>
- {
- /// Function new creates a blank Grid
- pub fn new() -> Grid<CellDataType, MetaDataType> {
- let temp_grid_data: GridDataType<CellDataType> = GridDataType {
- data: Vec::new(),
- dimensions: Vec::new(),
- };
- Grid {
- data_a: RefCell::new(temp_grid_data.clone()),
- data_b: RefCell::new(temp_grid_data.clone()),
- direction: Cell::new(true),
- meta: util::Newable::new(),
- }
- }
- /// Function get_data gets the most recent data from the struct
- pub fn get_data(&self) -> Ref<GridDataType<CellDataType>> {
- let tmp = {
- if self.direction.get() {
- &self.data_a
- } else {
- &self.data_b
- }
- };
- if let Ok(a) = tmp.try_borrow() {
- a
- } else {
- panic!("Cannot borrow data");
- }
- }
- /// Function get_meta gets the MetaData
- pub fn get_meta(&self) -> &MetaDataType {
- &self.meta
- }
- /// Function read_from_string reads a Grid from a string - mutating the object
- pub fn read_from_str(&mut self, data: &str) {
- *self = Self::decode(data);
- }
- /// Function decode decodes the data into a Grid type.
- pub fn decode(input: &str) -> Grid<CellDataType, MetaDataType> {
- let split: Vec<String> = util::parse_table_sections(input); // Tokenize by semicolons, which seperates the data from the "metadata" - the "metadata" are things like the dimensions, and the "data" is the actual cell state
- if split.len() != 2 {
- // as of now, there are 2 "big tokens" (seperated by semicolons) - the first is the metadata (information about the rules, for example) and the second is the data.
- println!("ERROR - malformed input file.");
- panic!("ERROR - malformed input file.");
- }
- let meta_data_str: &str = &split[0];
- let meta_data: MetaDataType = util::Parseable::parse(meta_data_str);
- let dimensions = meta_data.get_dimensions();
- //let split_data: Vec<&str> = split[1].split(',').collect(); // Same as previous, but this time for the actual data, not the dimensions
- let data: Vec<CellDataType> = util::parse_csv_list(&split[1], ',');
- //let mut data: Vec<CellDataType> = Vec::new();
- //for j in split_data {
- // data.push(util::Parseable::parse(&String::from(j)[..]));
- //}
- let generated_data: GridDataType<CellDataType> = GridDataType {
- data,
- dimensions: dimensions.to_vec(),
- };
- Grid {
- data_a: RefCell::new(generated_data.clone()),
- data_b: RefCell::new(generated_data.clone()),
- direction: Cell::new(true),
- meta: meta_data,
- }
- }
- /// Function encode encodes the Grid in a string. INTERNAL
- pub fn encode(&self) -> String {
- let mut to_return: String = String::new();
- let active_data: Ref<GridDataType<CellDataType>> = {
- if self.direction.get() {
- if let Ok(a) = self.data_a.try_borrow() {
- a
- } else {
- panic!("Cannot borrow active data (currently data_a) immutably");
- }
- } else if let Ok(a) = self.data_b.try_borrow() {
- a
- } else {
- panic!("Cannot borrow active data (currently data_b) immutably");
- }
- };
- for j in &active_data.dimensions {
- to_return += &j.to_string();
- to_return += ",";
- }
- to_return += ";";
- for j in &active_data.data {
- to_return += &util::Encodeable::encode(j)[..];
- to_return += ",";
- }
- to_return
- }
- /// compute_internal is an internal computation function
- #[inline]
- fn compute_internal(
- static_args: &StaticExecArgs<'_, CellDataType, MetaDataType>,
- dynamic_args: &mut DynamicExecArgs<'_, CellDataType>,
- ) {
- for j in (dynamic_args.low)..(dynamic_args.high) {
- (static_args.transition)(
- &mut dynamic_args.to_write[j - dynamic_args.low],
- &(static_args.neighbor_parser)(&static_args.to_read, static_args.meta, j),
- static_args.meta,
- );
- }
- }
- #[inline(always)]
- fn mainloop_internal<'c>(
- addr_start: usize,
- addr_end: usize,
- static_args: &StaticExecArgs<'_, CellDataType, MetaDataType>,
- run: &RunFunc<CellDataType, MetaDataType>,
- to_modify_data: &'c mut [CellDataType],
- ) -> &'c mut [CellDataType] {
- let (head, tail): (&'c mut [CellDataType], &'c mut [CellDataType]) =
- //to_modify.data.split_at_mut(chunk_size * (j + 1));
- to_modify_data.split_at_mut(addr_end - addr_start);
- run(
- &Self::compute_internal,
- &static_args,
- &mut DynamicExecArgs::new(addr_start, addr_end, head), //&mut DynamicExecArgs::new(j * chunk_size, (j+1) * chunk_size, to_modify.data.split_at_mut(chunk_size * (j+1)).1)
- );
- tail
- }
- /// Function apply performs one iteration
- #[inline]
- pub fn apply(
- &self,
- transition: &TransitionFunc<CellDataType, MetaDataType>,
- neighbor_parser: &NeighborFuncParser<CellDataType, MetaDataType>,
- run: &RunFunc<CellDataType, MetaDataType>,
- distribute_count: usize,
- meta: &MetaDataType,
- )
- {
- let (mut to_modify, to_read): (
- RefMut<GridDataType<CellDataType>>,
- Ref<GridDataType<CellDataType>>,
- ) = {
- if self.direction.get() {
- let borrowed_mut = {
- if let Ok(a) = self.data_a.try_borrow_mut() {
- a
- } else {
- panic!("Cannot borrow to_write");
- }
- };
- let borrowed = {
- if let Ok(a) = self.data_b.try_borrow() {
- a
- } else {
- panic!("Cannot borrow to_read");
- }
- };
- (borrowed_mut, borrowed)
- } else {
- let borrowed_mut = {
- if let Ok(a) = self.data_b.try_borrow_mut() {
- a
- } else {
- panic!("Cannot borrow to_write");
- }
- };
- let borrowed = {
- if let Ok(a) = self.data_a.try_borrow() {
- a
- } else {
- panic!("Cannot borrow to_read");
- }
- };
- (borrowed_mut, borrowed)
- }
- };
- let mut to_modify_data = to_modify.get_data_mut_slice();
- let data_len = to_read.get_data().len();
- let static_args = StaticExecArgs::new(transition, neighbor_parser, to_read, meta);
- let chunk_size: usize = (data_len) / distribute_count;
- let mut addr = 0;
- for j in 0..distribute_count {
- addr += chunk_size;
- /*let (head, tail): (&mut [CellDataType], &mut [CellDataType]) =
- to_modify_data.split_at_mut(chunk_size);
- run(
- &Self::compute_internal,
- &static_args,
- &mut DynamicExecArgs::new(j * chunk_size, (j + 1) * chunk_size, head), //&mut DynamicExecArgs::new(j * chunk_size, (j+1) * chunk_size, to_modify.data.split_at_mut(chunk_size * (j+1)).1)
- );*/
- to_modify_data = Self::mainloop_internal(
- j * chunk_size,
- (j + 1) * chunk_size,
- &static_args,
- run,
- &mut to_modify_data,
- );
- }
- if addr != data_len {
- let diff = data_len - addr;
- /*let (head, _tail): (&mut [CellDataType], &mut [CellDataType]) =
- to_modify_data.split_at_mut(chunk_size);
- run(
- &Self::compute_internal,
- &static_args,
- &mut DynamicExecArgs::new(data_len - diff, data_len, head)
- );*/
- Self::mainloop_internal(diff, data_len, &static_args, run, &mut to_modify_data);
- }
- self.direction.set(!self.direction.get());
- }
- }
- /// `ParseGridError` is a unit struct that signals a grid parsing error
- pub struct ParseGridError {}
- impl<
- CellDataType: 'static + Clone + util::Newable + util::Parseable + util::Encodeable,
- MetaDataType: 'static + Clone + util::Newable + util::Parseable + GridMeta,
- > FromStr for Grid<CellDataType, MetaDataType>
- {
- type Err = ParseGridError;
- /// Function from_str parses a Grid from a string. Does not mutate the object.
- fn from_str(data: &str) -> Result<Grid<CellDataType, MetaDataType>, Self::Err> {
- let mut temp = Grid::new();
- temp.read_from_str(data);
- Ok(temp)
- }
- }
- impl<CellDataType: Clone> GridDataType<CellDataType> {
- pub fn new(dimensions: &[usize]) -> GridDataType<CellDataType> {
- GridDataType {
- data: Vec::new(),
- dimensions: dimensions.to_vec(),
- }
- }
- pub fn from_data(data: &[CellDataType], dimensions: &[usize]) -> GridDataType<CellDataType> {
- GridDataType {
- data: data.to_vec(),
- dimensions: dimensions.to_vec(),
- }
- }
- pub fn get_data_ref(&self) -> &Vec<CellDataType> {
- &self.data
- }
- pub fn get_data_mut_slice(&mut self) -> &mut [CellDataType] {
- self.data.as_mut_slice()
- }
- pub fn get_dimensions_ref(&self) -> &Vec<usize> {
- &self.dimensions
- }
- pub fn get_data(&self) -> Vec<CellDataType> {
- self.data.clone()
- }
- pub fn get_dimensions(&self) -> Vec<usize> {
- self.dimensions.clone()
- }
- }
- impl<'a, CellDataType: Clone> NeighborType<'a, CellDataType> {
- pub fn new(
- data_1: Vec<&'a CellDataType>,
- dimensions_1: &'a [usize],
- ) -> NeighborType<'a, CellDataType> {
- NeighborType {
- data: data_1,
- dimensions: &dimensions_1,
- }
- }
- pub fn get_data(&self) -> Vec<&'a CellDataType> {
- self.data.clone()
- }
- }
- impl<'a, CellDataType, MetaDataType: util::Newable + util::Parseable + GridMeta>
- StaticExecArgs<'a, CellDataType, MetaDataType>
- {
- fn new(
- transition_1: &'a TransitionFunc<CellDataType, MetaDataType>,
- neighbor_parser_1: &'a NeighborFuncParser<CellDataType, MetaDataType>,
- to_read_1: Ref<'a, GridDataType<CellDataType>>,
- meta_1: &'a MetaDataType,
- ) -> StaticExecArgs<'a, CellDataType, MetaDataType> {
- StaticExecArgs {
- transition: transition_1,
- neighbor_parser: neighbor_parser_1,
- to_read: to_read_1,
- meta: meta_1,
- }
- }
- }
- impl<'a, CellDataType> DynamicExecArgs<'a, CellDataType> {
- fn new(
- low_1: usize,
- high_1: usize,
- to_write_1: &'a mut [CellDataType],
- ) -> DynamicExecArgs<'a, CellDataType> {
- DynamicExecArgs {
- low: low_1,
- high: high_1,
- to_write: to_write_1,
- }
- }
- }
Add Comment
Please, Sign In to add comment