From 36e4baa9c336bd5ec7d1aa5ef19ef1c65fde0ab6 Mon Sep 17 00:00:00 2001 From: Datawater <86855332+datawater@users.noreply.github.com> Date: Sat, 6 Jul 2024 01:59:53 +0400 Subject: [PATCH] Minor changes Switched to TCMalloc, Added doc comments --- Cargo.lock | 7 +++++ Cargo.toml | 1 + NOTICE.html | 3 +- libcmbr/Cargo.toml | 5 +++ libcmbr/src/cmbr/error.rs | 2 ++ libcmbr/src/cmbr/flags.rs | 60 +++++++++++++++++++----------------- libcmbr/src/cmbr/mod.rs | 1 + libcmbr/src/cmbr/tests.rs | 4 ++- libcmbr/src/cmbr/u24_impl.rs | 1 + libcmbr/src/lib.rs | 11 +++++++ libcmbr/src/pgn/ast.rs | 12 +++++++- libcmbr/src/pgn/mod.rs | 4 ++- libcmbr/src/pgn/tests.rs | 8 +++-- libcmbr/src/utils.rs | 2 +- scripts/checkunsafe.py | 15 ++++++--- src/eval_args.rs | 9 +++--- 16 files changed, 101 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43d7001..72a5b71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,7 @@ dependencies = [ "pgn-lexer", "project-root", "shakmaty", + "tcmalloc", ] [[package]] @@ -132,3 +133,9 @@ dependencies = [ "bitflags", "btoi", ] + +[[package]] +name = "tcmalloc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375205113d84a1c5eeed67beaa0ce08e41be1a9d5acc3425ad2381fddd9d819b" diff --git a/Cargo.toml b/Cargo.toml index bac5be3..dc618a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ benchmark = [] lto = "fat" incremental = false codegen-units = 1 +panic = "abort" [profile.dev] opt-level = 1 diff --git a/NOTICE.html b/NOTICE.html index 50c2d0c..9419488 100644 --- a/NOTICE.html +++ b/NOTICE.html @@ -44,7 +44,7 @@
Apache License Version 2.0, January 2004 diff --git a/libcmbr/Cargo.toml b/libcmbr/Cargo.toml index dfa10c2..0d0a22e 100644 --- a/libcmbr/Cargo.toml +++ b/libcmbr/Cargo.toml @@ -11,8 +11,13 @@ pgn-lexer = { git = "https://github.com/datawater/pgn-lexer" } shakmaty = "0.27.0" [features] +default = ["tcmalloc"] safe_u24 = [] benchmark = [] +tcmalloc = ["dep:tcmalloc"] [dev-dependencies] project-root = "0.2.2" + +[target.'cfg(not(target_env = "msvc"))'.dependencies] +tcmalloc = { version = "0.3.0", optional = true } diff --git a/libcmbr/src/cmbr/error.rs b/libcmbr/src/cmbr/error.rs index da0fa2a..90f7c6a 100644 --- a/libcmbr/src/cmbr/error.rs +++ b/libcmbr/src/cmbr/error.rs @@ -5,6 +5,7 @@ use std::fmt; #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[repr(u8)] +/// An enum denoting each error libcmbr can give pub enum LibCmbrErrorType { #[default] Ok = 0, @@ -12,6 +13,7 @@ pub enum LibCmbrErrorType { CrazyHouseNotSupported, } +// A struct with libcmbr reports errors #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct LibCmbrError { kind: LibCmbrErrorType, diff --git a/libcmbr/src/cmbr/flags.rs b/libcmbr/src/cmbr/flags.rs index 545c148..9367e37 100644 --- a/libcmbr/src/cmbr/flags.rs +++ b/libcmbr/src/cmbr/flags.rs @@ -1,35 +1,39 @@ use crate::utils::def_enum; -def_enum! (pub CmbrFlags => u8{ - FlagNone => 0, - FlagCheck => 1 << 0, - FlagMate => 1 << 1, - FlagCapture => 1 << 2, - FlagNag => 1 << 3, // If this flag is set, the first 8 bits of the CMBR are replaced with a NAG index (https://w.wiki/AWUT) +def_enum! ( + #[doc = "An enum donating the flags that a CMBR-MV Can have"] + pub CmbrFlags => u8{ + FlagNone => 0, + FlagCheck => 1 << 0, + FlagMate => 1 << 1, + FlagCapture => 1 << 2, + FlagNag => 1 << 3, // If this flag is set, the first 8 bits of the CMBR are replaced with a NAG index (https://w.wiki/AWUT) - FlagPromotesBishop => (1 << 6) | 0b000000, - FlagPromotesKnight => (1 << 6) | 0b010000, - FlagPromotesRook => (1 << 6) | 0b100000, - FlagPromotesQueen => (1 << 6) | 0b110000, + FlagPromotesBishop => (1 << 6) | 0b000000, + FlagPromotesKnight => (1 << 6) | 0b010000, + FlagPromotesRook => (1 << 6) | 0b100000, + FlagPromotesQueen => (1 << 6) | 0b110000, - FlagIsVariationPointer => 1 << 7 // If this flag is set, the first 16 bits of the CMBR are replaced with an index to the table of variations + FlagIsVariationPointer => 1 << 7 // If this flag is set, the first 16 bits of the CMBR are replaced with an index to the table of variations }); -def_enum! (pub CmbrPiece => u8{ - WhitePawn => 0b0000, - WhiteKnight => 0b0001, - WhiteBishop => 0b0010, - WhiteRook => 0b0011, - WhiteQueen => 0b0100, - WhiteKing => 0b0101, - WhiteShortCastle => 0b0110, - WhiteLongCaslte => 0b0111, - BlackPawn => 0b1000, - BlackKnight => 0b1001, - BlackBishop => 0b1010, - BlackRook => 0b1011, - BlackQueen => 0b1100, - BlackKing => 0b1101, - BlackShortCastle => 0b1110, - BlackLongCaslte => 0b1111, +def_enum! ( + #[doc = "An enum donating the Piece that a CMBR-MV Can have"] + pub CmbrPiece => u8{ + WhitePawn => 0b0000, + WhiteKnight => 0b0001, + WhiteBishop => 0b0010, + WhiteRook => 0b0011, + WhiteQueen => 0b0100, + WhiteKing => 0b0101, + WhiteShortCastle => 0b0110, + WhiteLongCaslte => 0b0111, + BlackPawn => 0b1000, + BlackKnight => 0b1001, + BlackBishop => 0b1010, + BlackRook => 0b1011, + BlackQueen => 0b1100, + BlackKing => 0b1101, + BlackShortCastle => 0b1110, + BlackLongCaslte => 0b1111, }); diff --git a/libcmbr/src/cmbr/mod.rs b/libcmbr/src/cmbr/mod.rs index 4031455..e855b85 100644 --- a/libcmbr/src/cmbr/mod.rs +++ b/libcmbr/src/cmbr/mod.rs @@ -59,6 +59,7 @@ fn shakmaty_suffix_to_flag(suffix: Suffix) -> u8 { }; } +/// Inputs a SAN string and generates a CMBR-MV from it pub fn san_to_cmbr(board: &mut Chess, san_bytes: &[u8]) -> Result> { // safe if called correctly. let san_string = unsafe { std::str::from_utf8_unchecked(san_bytes) }; diff --git a/libcmbr/src/cmbr/tests.rs b/libcmbr/src/cmbr/tests.rs index f7df63a..b092a7d 100644 --- a/libcmbr/src/cmbr/tests.rs +++ b/libcmbr/src/cmbr/tests.rs @@ -80,7 +80,9 @@ mod cmbr_tests { #[cfg(feature = "benchmark")] #[bench] fn bench_san_cmbr(b: &mut Bencher) { - let file_path = get_project_root().unwrap().join("data/twic1544.pgn"); + let file_path = get_project_root() + .unwrap() + .join("data/fischer_spassky_1992.pgn"); let file = File::open(file_path.clone()); if file.is_err() { diff --git a/libcmbr/src/cmbr/u24_impl.rs b/libcmbr/src/cmbr/u24_impl.rs index 5c8cb54..3357675 100644 --- a/libcmbr/src/cmbr/u24_impl.rs +++ b/libcmbr/src/cmbr/u24_impl.rs @@ -8,6 +8,7 @@ use std::ops::{ #[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)] #[allow(non_camel_case_types)] +/// Unsigned 24bit integer pub struct u24([u8; 3]); impl u24 { diff --git a/libcmbr/src/lib.rs b/libcmbr/src/lib.rs index 2807dd2..7b18348 100644 --- a/libcmbr/src/lib.rs +++ b/libcmbr/src/lib.rs @@ -1,6 +1,17 @@ #![allow(non_upper_case_globals)] #![feature(test)] +// TODO: Experiment with different allocators +// Since our program is memory-usage intensive, different allocators may provide performance speedups and use less memory + +// NOTE: With TCMAlloc the program is just slightly faster (by like 400ns/iter) +#[cfg(all(not(target_env = "msvc"), feature = "tcmalloc"))] +use tcmalloc::TCMalloc; + +#[cfg(all(not(target_env = "msvc"), feature = "tcmalloc"))] +#[global_allocator] +static ALLOCATOR: TCMalloc = TCMalloc; + pub mod cmbr; pub mod pgn; // mod tests; diff --git a/libcmbr/src/pgn/ast.rs b/libcmbr/src/pgn/ast.rs index 735d265..dc818dd 100644 --- a/libcmbr/src/pgn/ast.rs +++ b/libcmbr/src/pgn/ast.rs @@ -6,21 +6,31 @@ use std::collections::VecDeque; // TODO(#16): Implement tests for ast generating // TODO(#17): Oh shit, currently this program uses 12x the memory of the input file :sob: maybe reduce that ?? +/// An enumeration representing different types of PGN tokens. #[derive(Debug, Clone, Default, PartialEq, Eq)] pub enum PgnToken<'a> { + /// Represents a token specific to the game, such as a move, header, or result. Token(Token<'a>), + /// Represents a pointer to a variation. VariationPointer(u16), + /// Represents no token. This is the default variant. #[default] None, } +/// A structure representing a PGN variation, which is a series of PGN tokens. #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct PgnVariation<'a>(pub Vec >); +/// A structure representing a PGN game. +/// +/// This consists of: +/// - A vector of tokens specific to the game, such as headers and results. +/// - A map of variations, indexed by their respective pointers. #[derive(Debug, Clone, Default, PartialEq, Eq)] -// (`Tokens specific to the game, such as headers, results, etc.`, A map of variations) pub struct PgnGame<'a>(pub (Vec >, LiteMap >)); +/// Builds an ast (represented as `a Vec `) from the inputted Token list pub fn build_pgn_ast<'a>(tokens: &mut VecDeque >) -> Vec > { let mut tree: Vec > = Vec::new(); let mut game_number = 0; diff --git a/libcmbr/src/pgn/mod.rs b/libcmbr/src/pgn/mod.rs index 15d95b5..efb8c7e 100644 --- a/libcmbr/src/pgn/mod.rs +++ b/libcmbr/src/pgn/mod.rs @@ -1,6 +1,6 @@ pub mod ast; -mod tests; pub use ast::*; +mod tests; use std::collections::VecDeque; @@ -8,6 +8,7 @@ use memmap2::Mmap; use pgn_lexer::parser; pub use pgn_lexer::parser::Token; +/// Lexes a PGN file (Generates a `Vec `) from the given Mmap pub fn lex_pgn<'a>(input_mmap: &'a mut Mmap) -> VecDeque > { let mut bytes = &input_mmap[..]; if bytes[0..3] == [239u8, 187u8, 191u8] { @@ -19,6 +20,7 @@ pub fn lex_pgn<'a>(input_mmap: &'a mut Mmap) -> VecDeque > { return tokens.collect(); } +/// First lexes mmap, then generates AST and returns pub fn parse_pgn<'a>(input_mmap: &'a mut Mmap) -> Vec > { return build_pgn_ast(&mut lex_pgn(input_mmap)); } diff --git a/libcmbr/src/pgn/tests.rs b/libcmbr/src/pgn/tests.rs index 34b8ce2..84a693d 100644 --- a/libcmbr/src/pgn/tests.rs +++ b/libcmbr/src/pgn/tests.rs @@ -46,7 +46,9 @@ mod pgn_tests { #[cfg(feature = "benchmark")] #[bench] fn bench_ast(b: &mut Bencher) { - let file_path = get_project_root().unwrap().join("data/twic1544.pgn"); + let file_path = get_project_root() + .unwrap() + .join("data/fischer_spassky_1992.pgn"); let file = File::open(file_path.clone()); if file.is_err() { @@ -174,7 +176,9 @@ mod pgn_tests { #[cfg(feature = "benchmark")] #[bench] fn bench_lex(b: &mut Bencher) { - let file_path = get_project_root().unwrap().join("data/twic1544.pgn"); + let file_path = get_project_root() + .unwrap() + .join("data/fischer_spassky_1992.pgn"); let file = File::open(file_path.clone()); if file.is_err() { diff --git a/libcmbr/src/utils.rs b/libcmbr/src/utils.rs index d9edd24..64d1a44 100644 --- a/libcmbr/src/utils.rs +++ b/libcmbr/src/utils.rs @@ -2,7 +2,7 @@ use std::ops::{BitAnd, Shl, Shr, Sub}; // Macro stolen from https://stackoverflow.com/a/62759540 macro_rules! def_enum { - ($vis:vis $name:ident => $ty:ty { + ($(#[$outer:meta])* $vis:vis $name:ident => $ty:ty { $($variant:ident => $val:expr),+ $(,)? }) => { diff --git a/scripts/checkunsafe.py b/scripts/checkunsafe.py index f4b49d1..f0739a1 100755 --- a/scripts/checkunsafe.py +++ b/scripts/checkunsafe.py @@ -1,5 +1,12 @@ #!/bin/python3 +# Utility checking for unsafes in the code that don't have an override calling them safe. Ex: + # This is reported as unsafe + # let x = unsafe { std::mem::zeroed() }; + # However this, is not: + # // SAFE: Safe + # let x = unsafe { std::mem::zeroed() }; + import re import sys @@ -18,12 +25,12 @@ def main(): print("Expected input file. Usage:") usage() return - + if argv[argc_i] == "-h" or argv[argc_i] == "--help": print("Usage:") usage() return - + file = open(argv[argc_i]) lines = file.readlines() @@ -33,10 +40,10 @@ def main(): if is_unsafe and i == 0: print(f"{argv[argc_i]}:{i}") continue - + last_line_is_comment = re.search(safe_comment_regex, lines[i - 1]) if is_unsafe and not last_line_is_comment: print(f"{argv[argc_i]}:{i + 1}") continue -main() \ No newline at end of file +main() diff --git a/src/eval_args.rs b/src/eval_args.rs index cfc8d6f..f29d16a 100644 --- a/src/eval_args.rs +++ b/src/eval_args.rs @@ -7,8 +7,6 @@ use std::fs::File; use std::io::Write; pub fn eval_args(cli: &Cli) { - use std::process::exit; - match cli.command.as_ref().unwrap() { crate::CommandE::Cmbr2pgn(_args) => { // TODO(#1): Implement CMBR2PGN @@ -21,7 +19,7 @@ pub fn eval_args(cli: &Cli) { if file.is_err() { eprintln!("[ERROR] {}. File name: {file_name}", file.err().unwrap()); - exit(1); + std::process::exit(1); } // SAFE: Safe @@ -30,7 +28,7 @@ pub fn eval_args(cli: &Cli) { if mmap.is_err() { eprintln!("[ERROR] {}. File name: {file_name}", mmap.err().unwrap()); - exit(1); + std::process::exit(1); } // SAFE: Safe @@ -59,6 +57,7 @@ pub fn eval_args(cli: &Cli) { } let mut f = File::create(&args.output).unwrap(); + // SAFE: Safe f.write_all(unsafe { std::slice::from_raw_parts( cmbrs.as_ptr() as *const u8, @@ -77,7 +76,7 @@ pub fn eval_args(cli: &Cli) { println!("under the conditions of the GPL-3.0 License;"); println!("\nSee https://github.com/datawater/cmbr"); - exit(0); + std::process::exit(0); } } }