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 @@

Third Party Licenses

Overview of licenses:

                              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);
         }
     }
 }