diff --git a/Cargo.toml b/Cargo.toml index d2f1d2d..5c1a8ef 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,12 +51,12 @@ rand_pcg = "0.3.1" hashbrown = "0.12.1" indexmap = "1.8.2" parking_lot = "0.12.1" -conquer-once = "0.3.2" serde = { version = "1.0.137", optional = true, features = ["derive"] } wasmer = { version = "3.0.0-beta", optional = true, default-features = true } unique-type-id = { version = "1.0.0", optional = true } unique-type-id-derive = { version = "1.0.0", optional = true } paste = { version = "1.0.8" } +arcstr = "1.1.4" [dev-dependencies] csv = "1.1.6" diff --git a/lifetime_notes.txt b/lifetime_notes.txt deleted file mode 100755 index 87469ce..0000000 --- a/lifetime_notes.txt +++ /dev/null @@ -1,5 +0,0 @@ -Main lifetimes: -- Library: the static data underlying everything. This has the longest lifetime. -- Pokemon: The lifetime of a Pokemon. -- Party: The lifetime of a party, as a Pokemon can be added or taken from a party, this is shorter than the lifetime of a pokemon -- Battle: The lifetime of a battle. diff --git a/src/dynamic_data/script_handling/mod.rs b/src/dynamic_data/script_handling/mod.rs index 5a16fb9..54fab5f 100755 --- a/src/dynamic_data/script_handling/mod.rs +++ b/src/dynamic_data/script_handling/mod.rs @@ -239,7 +239,7 @@ mod tests { impl TestScript { fn new() -> Self { Self { - name: StringKey::new("test"), + name: StringKey::new("test".into()), is_marked_for_deletion: Default::default(), suppressed_count: AtomicUsize::new(0), test_count: AtomicUsize::new(0), @@ -247,7 +247,7 @@ mod tests { } fn new_with_name(name: &str) -> Self { Self { - name: StringKey::new(name), + name: StringKey::new(name.into()), is_marked_for_deletion: Default::default(), suppressed_count: AtomicUsize::new(0), test_count: AtomicUsize::new(0), @@ -424,7 +424,7 @@ mod tests { "test_b" ); - set.remove(&StringKey::new("test_c")); + set.remove(&StringKey::new("test_c".into())); assert!(aggregator.get_next().is_none()); } @@ -451,7 +451,7 @@ mod tests { "test_a" ); - set.remove(&StringKey::new("test_b")); + set.remove(&StringKey::new("test_b".into())); assert_eq!( aggregator diff --git a/src/dynamic_data/script_handling/script.rs b/src/dynamic_data/script_handling/script.rs index 024109c..1d8e8ae 100755 --- a/src/dynamic_data/script_handling/script.rs +++ b/src/dynamic_data/script_handling/script.rs @@ -398,7 +398,7 @@ mod tests { impl TestScript { fn new() -> Self { Self { - name: StringKey::new("test"), + name: StringKey::new("test".into()), container: AtomicPtr::::default(), suppressed_count: AtomicUsize::new(0), marked_for_deletion: Default::default(), @@ -539,7 +539,7 @@ mod tests { assert_eq!( container.script.read().as_ref().unwrap().name(), - &StringKey::new("script2") + &StringKey::new("script2".into()) ); } } diff --git a/src/lib.rs b/src/lib.rs index 71100fb..15b08de 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ #![feature(is_some_with)] #![feature(new_uninit)] #![feature(get_mut_unchecked)] +#![feature(strict_provenance)] //! PkmnLib //! PkmnLib is a full featured implementation of Pokemon. while currently focused on implementing diff --git a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs index be9aabd..117f55b 100755 --- a/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs +++ b/src/script_implementations/wasm/export_registry/dynamic_data/pokemon.rs @@ -194,7 +194,7 @@ register! { ) -> u8 { let name : *mut c_char = env.data().data().get_raw_pointer(name); let name = unsafe { CStr::from_ptr(name) }; - let key = StringKey::new(&name.to_str().unwrap().clone()); + let key = StringKey::new(name.to_str().unwrap().into()); if pokemon.value_func(&env).unwrap().has_held_item(&key) { 1 } else { 0 } } diff --git a/src/static_data/libraries/ability_library.rs b/src/static_data/libraries/ability_library.rs index 25d85e0..5a57823 100755 --- a/src/static_data/libraries/ability_library.rs +++ b/src/static_data/libraries/ability_library.rs @@ -41,7 +41,7 @@ pub mod tests { pub fn build() -> AbilityLibrary { let mut lib = AbilityLibrary::new(1); lib.add( - &StringKey::new("test_ability"), + &StringKey::new("test_ability".into()), Ability::new(&"test_ability".into(), &"test_ability".into(), Vec::new()), ); // Drops borrow as mut diff --git a/src/static_data/libraries/move_library.rs b/src/static_data/libraries/move_library.rs index e40c19b..9e943b4 100755 --- a/src/static_data/libraries/move_library.rs +++ b/src/static_data/libraries/move_library.rs @@ -61,7 +61,7 @@ pub mod tests { let m = build_move(); // Borrow as mut so we can insert let w = &mut lib; - w.add(&StringKey::new("foo"), m); + w.add(&StringKey::new("foo".into()), m); // Drops borrow as mut lib diff --git a/src/static_data/species_data/species.rs b/src/static_data/species_data/species.rs index 2520a7d..1885b56 100755 --- a/src/static_data/species_data/species.rs +++ b/src/static_data/species_data/species.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::sync::{Arc, LazyLock}; use hashbrown::{HashMap, HashSet}; @@ -29,11 +29,11 @@ pub struct Species { } /// A cached String Key to get the default form. -static DEFAULT_KEY: conquer_once::OnceCell = conquer_once::OnceCell::uninit(); +static DEFAULT_KEY: LazyLock = LazyLock::new(|| StringKey::new("default")); /// Gets the StringKey for "default". Initialises it if it does not exist. fn get_default_key() -> StringKey { - DEFAULT_KEY.get_or_init(|| StringKey::new("default")).clone() + DEFAULT_KEY.clone() } impl Species { diff --git a/src/utils/string_key.rs b/src/utils/string_key.rs index ce57b55..4deacdc 100755 --- a/src/utils/string_key.rs +++ b/src/utils/string_key.rs @@ -1,12 +1,12 @@ +use arcstr::ArcStr; +use hashbrown::HashMap; +use parking_lot::RwLock; use std::borrow::Borrow; use std::ffi::CStr; use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use std::sync::{Arc, Mutex, Weak}; - -use conquer_once::OnceCell; -use hashbrown::HashMap; +use std::sync::LazyLock; /// StringKey is an immutable string that is used for indexing of hashmaps or equality a lot. /// By reference counting the string instead of copying, and caching the hash, we can get some @@ -16,16 +16,16 @@ use hashbrown::HashMap; #[cfg_attr(feature = "wasm", derive(unique_type_id_derive::UniqueTypeId))] pub struct StringKey { /// The underlying reference counted string. - str: Arc, + str: ArcStr, /// The unique hash of the string. hash: u32, } /// A cache of all allocated strings. This allows us to re-use strings that are often used without /// allocation. -static STRING_CACHE: OnceCell>>> = OnceCell::uninit(); +static STRING_CACHE: LazyLock>> = LazyLock::new(|| RwLock::new(HashMap::new())); /// An empty StringKey -static EMPTY: OnceCell = OnceCell::uninit(); +static EMPTY: LazyLock = LazyLock::new(|| StringKey::new("")); impl StringKey { /// Gets the hash of a string. @@ -42,25 +42,29 @@ impl StringKey { /// Creates a new StringKey. If we can find a value for this StringKey in the cache, we re-use /// that value. pub fn new(s: &str) -> Self { - let hash = StringKey::get_hash(s); - let mut cache = STRING_CACHE.get_or_init(|| Mutex::new(HashMap::new())).lock().unwrap(); - let cached_value = cache.get(&hash); - if let Some(cached_value) = cached_value { - if let Some(cached_value) = cached_value.upgrade() { + let s: ArcStr = s.into(); + let hash = StringKey::get_hash(s.as_str()); + { + let cache_read = STRING_CACHE.read(); + let cached_value = cache_read.get(&hash); + if let Some(cached_value) = cached_value { return Self { - str: cached_value, + str: cached_value.clone(), hash, }; } } - let v = Self { str: s.into(), hash }; - cache.insert(hash, Arc::downgrade(&v.str)); - v + { + let v = Self { str: s.clone(), hash }; + let mut cache_write = STRING_CACHE.write(); + cache_write.insert(hash, s); + v + } } /// Gets the empty StringKey. pub fn empty() -> Self { - EMPTY.get_or_init(|| StringKey::new("")).clone() + EMPTY.clone() } /// Gets the underlying string for the StringKey. @@ -108,7 +112,7 @@ impl Display for StringKey { impl Into for &CStr { fn into(self) -> StringKey { - StringKey::new(self.to_str().unwrap()) + StringKey::new(self.to_str().unwrap().into()) } } /// Converts a character to lowercased in a const safe way. @@ -160,7 +164,7 @@ mod tests { #[test] fn create_empty_stringkey() { - let sk = StringKey::new(""); + let sk = StringKey::new("".into()); assert_eq!(sk.str(), ""); assert_eq!(sk.hash(), 0); assert_eq!(sk.hash(), StringKey::get_hash("")); @@ -168,7 +172,7 @@ mod tests { #[test] fn create_stringkey_foo() { - let sk = StringKey::new("foo"); + let sk = StringKey::new("foo".into()); assert_eq!(sk.str(), "foo"); assert_eq!(sk.hash(), 2356372769); assert_eq!(sk.hash(), StringKey::get_hash("foo")); @@ -177,7 +181,7 @@ mod tests { #[test] fn create_stringkey_bar() { - let sk = StringKey::new("bar"); + let sk = StringKey::new("bar".into()); assert_eq!(sk.str(), "bar"); assert_eq!(sk.hash(), 1996459178); assert_eq!(sk.hash(), StringKey::get_hash("bar")); diff --git a/tests/common/library_loader.rs b/tests/common/library_loader.rs index f3aeac2..a4eee17 100755 --- a/tests/common/library_loader.rs +++ b/tests/common/library_loader.rs @@ -52,13 +52,13 @@ pub fn load_types(path: &String, type_library: &mut TypeLibrary) { .unwrap(); let headers = reader.headers().unwrap(); for header in headers.iter().skip(1) { - type_library.register_type(&StringKey::new(header)); + type_library.register_type(&StringKey::new(header.into())); } for record in reader.records() { let record = record.unwrap(); let offensive_type = record.get(0).unwrap(); - let offensive_type_id = type_library.get_type_id(&StringKey::new(offensive_type)); + let offensive_type_id = type_library.get_type_id(&StringKey::new(offensive_type.into())); for (i, v) in record.iter().skip(1).enumerate() { let effectiveness = v.parse::().unwrap(); @@ -75,7 +75,7 @@ pub fn load_natures(path: &String, nature_library: &mut NatureLibrary) { for record in reader.records() { let record = record.unwrap(); - let nature_name = StringKey::new(record.get(0).unwrap()); + let nature_name = StringKey::new(record.get(0).unwrap().into()); let increased_statistic_str = record.get(1).unwrap(); let decreased_statistic_str = record.get(2).unwrap(); if increased_statistic_str.is_empty() || decreased_statistic_str.is_empty() { @@ -99,18 +99,18 @@ pub fn load_items(path: &String, lib: &mut ItemLibrary) { let json_array = json.as_array().unwrap(); for v in json_array { - let name = StringKey::new(v["name"].as_str().unwrap()); - let category = serde_json::from_value(v["itemType"].clone()).unwrap(); + let name = StringKey::new(v.get("name").unwrap().as_str().unwrap().into()); + let category = serde_json::from_value(v.get("itemType").unwrap().clone()).unwrap(); let mut battle_category = BattleItemCategory::None; if let Some(c) = v.get("battleType") { battle_category = serde_json::from_value(c.clone()).unwrap(); } - let price = v["price"].as_i64().unwrap(); + let price = v.get("price").unwrap().as_i64().unwrap(); let mut flags = HashSet::new(); if let Some(f) = v.get("flags") { let a = f.as_array().unwrap(); for flag in a { - flags.insert(StringKey::new(flag.as_str().unwrap())); + flags.insert(StringKey::new(flag.as_str().unwrap().into())); } } @@ -148,7 +148,7 @@ pub fn load_abilities(path: &String, ability_library: &mut AbilityLibrary) { let name = StringKey::new(key); let mut effect = StringKey::empty(); if let Some(e) = value.get("effect") { - effect = StringKey::new(e.as_str().unwrap()); + effect = StringKey::new(e.as_str().unwrap().into()); } let mut parameters = Vec::new(); if let Some(p) = value.get("parameters") { @@ -169,15 +169,15 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { let data = json.as_object().unwrap().get("data").unwrap().as_array().unwrap(); for move_data in data { let move_data = move_data.as_object().unwrap(); - let move_name = StringKey::new(move_data["name"].as_str().unwrap()); - let move_type = StringKey::new(move_data["type"].as_str().unwrap()); + let move_name = StringKey::new(move_data.get("name").unwrap().as_str().unwrap().into()); + let move_type = StringKey::new(move_data.get("type").unwrap().as_str().unwrap().into()); let move_type_id = lib.types().get_type_id(&move_type); - let move_category = serde_json::from_value(move_data["category"].clone()).unwrap(); - let base_power = move_data["power"].as_i64().unwrap() as u8; - let accuracy = move_data["accuracy"].as_i64().unwrap() as u8; - let pp = move_data["pp"].as_i64().unwrap() as u8; - let target = serde_json::from_value(move_data["target"].clone()).unwrap(); - let priority = move_data["priority"].as_i64().unwrap() as i8; + let move_category = serde_json::from_value(move_data.get("category").unwrap().clone()).unwrap(); + let base_power = move_data.get("power").unwrap().as_i64().unwrap() as u8; + let accuracy = move_data.get("accuracy").unwrap().as_i64().unwrap() as u8; + let pp = move_data.get("pp").unwrap().as_i64().unwrap() as u8; + let target = serde_json::from_value(move_data.get("target").unwrap().clone()).unwrap(); + let priority = move_data.get("priority").unwrap().as_i64().unwrap() as i8; let secondary_effect = if let Some(v) = move_data.get("effect") { let mut chance = -1.0; if let Some(chance_value) = v.get("chance") { @@ -193,7 +193,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { Some(SecondaryEffect::new( chance, - StringKey::new(v["name"].as_str().unwrap()), + StringKey::new(v.get("name").unwrap().as_str().unwrap().into()), parameters, )) } else { @@ -204,7 +204,7 @@ pub fn load_moves(path: &String, lib: &mut StaticData) { if let Some(f) = move_data.get("flags") { let f = f.as_array().unwrap(); for flag in f { - flags.insert(StringKey::new(flag.as_str().unwrap())); + flags.insert(StringKey::new(flag.as_str().unwrap().into())); } } @@ -233,29 +233,29 @@ pub fn load_species(path: &String, library: &mut StaticData) { let json: Value = serde_json::from_str(&data).unwrap(); let o = json.as_object().unwrap(); - for (key, value) in o { + for (key, value) in o.iter() { if key.starts_with('$') { continue; } let name = StringKey::new(key); - let id = value["id"].as_i64().unwrap(); - let gender_rate = value["genderRatio"].as_f64().unwrap(); - let growth_rate_name = StringKey::new(value["growthRate"].as_str().unwrap()); - let _base_happiness = value["baseHappiness"].as_i64().unwrap(); - let catch_rate = value["catchRate"].as_i64().unwrap(); - let _color = value["color"].as_str().unwrap(); - // let egg_groups = value["eggGroups"] + let id = value.get("id").unwrap().as_i64().unwrap(); + let gender_rate = value.get("genderRatio").unwrap().as_f64().unwrap(); + let growth_rate_name = StringKey::new(value.get("growthRate").unwrap().as_str().unwrap().into()); + let _base_happiness = value.get("baseHappiness").unwrap().as_i64().unwrap(); + let catch_rate = value.get("catchRate").unwrap().as_i64().unwrap(); + let _color = value.get("color").unwrap().as_str().unwrap(); + // let egg_groups = value.get("eggGroups").unwrap() // .as_array() // .unwrap() // .iter() // .map(|&a| a.as_str().unwrap()) // .collect(); - let _egg_cycle = value["eggCycles"].as_i64().unwrap(); + let _egg_cycle = value.get("eggCycles").unwrap().as_i64().unwrap(); // TODO: tags // TODO: evolutions - let forms = value["formes"].as_object().unwrap(); - let default_form_value = &forms["default"]; + let forms = value.get("formes").unwrap().as_object().unwrap(); + let default_form_value = forms.get("default").unwrap(); let default_form = parse_form("default".into(), default_form_value, library); let species = Species::new( @@ -282,26 +282,28 @@ fn load_wasm(path: &String, library: &mut WebAssemblyScriptResolver) { fn parse_form(name: StringKey, value: &Value, library: &mut StaticData) -> Form { let mut abilities = Vec::new(); - for a in value["abilities"].as_array().unwrap() { - abilities.push(StringKey::new(a.as_str().unwrap())); + for a in value.get("abilities").unwrap().as_array().unwrap() { + abilities.push(StringKey::new(a.as_str().unwrap().into())); } let mut hidden_abilities = Vec::new(); - for a in value["hiddenAbilities"].as_array().unwrap() { - hidden_abilities.push(StringKey::new(a.as_str().unwrap())); + for a in value.get("hiddenAbilities").unwrap().as_array().unwrap() { + hidden_abilities.push(StringKey::new(a.as_str().unwrap().into())); } - let base_stats = parse_statistics(&value["baseStats"]); + let base_stats = parse_statistics(&value.get("baseStats").unwrap()); // TODO: ev reward - let height = value["height"].as_f64().unwrap(); - let weight = value["weight"].as_f64().unwrap(); - let base_experience = value["baseExp"].as_u64().unwrap(); - let types = value["types"] + let height = value.get("height").unwrap().as_f64().unwrap(); + let weight = value.get("weight").unwrap().as_f64().unwrap(); + let base_experience = value.get("baseExp").unwrap().as_u64().unwrap(); + let types = value + .get("types") + .unwrap() .as_array() .unwrap() .iter() - .map(|a| library.types().get_type_id(&StringKey::new(a.as_str().unwrap()))) + .map(|a| library.types().get_type_id(&StringKey::new(a.as_str().unwrap().into()))) .collect(); - let moves = parse_moves(&value["moves"], library.moves()); + let moves = parse_moves(&value.get("moves").unwrap(), library.moves()); Form::new( &name, @@ -364,10 +366,10 @@ where fn parse_moves(value: &Value, move_library: &MoveLibrary) -> LearnableMoves { let mut moves = LearnableMoves::default(); - let level_moves = value["levelMoves"].as_array().unwrap(); + let level_moves = value.get("levelMoves").unwrap().as_array().unwrap(); for level_move in level_moves { - let name = StringKey::new(level_move["name"].as_str().unwrap()); - let level = level_move["level"].as_u64().unwrap() as LevelInt; + let name = StringKey::new(level_move.get("name").unwrap().as_str().unwrap().into()); + let level = level_move.get("level").unwrap().as_u64().unwrap() as LevelInt; assert!(move_library.get(&name).is_some()); moves.add_level_move(level, &name); } @@ -388,7 +390,7 @@ fn parse_effect_parameter(value: &Value) -> EffectParameter { EffectParameter::Int(n.as_i64().unwrap()) } } - Value::String(s) => EffectParameter::String(StringKey::new(s.as_str())), + Value::String(s) => EffectParameter::String(StringKey::new(s.as_str().into())), Value::Array(_) => { panic!("Unexpected type") } @@ -408,8 +410,8 @@ fn test_type_library_loaded() { assert_eq!( lib.get_effectiveness( - lib.get_type_id(&StringKey::new("fire")), - &[lib.get_type_id(&StringKey::new("grass"))], + lib.get_type_id(&StringKey::new("fire".into())), + &[lib.get_type_id(&StringKey::new("grass".into()))], ), 2.0 ); diff --git a/tests/common/test_case.rs b/tests/common/test_case.rs index ea0e19d..1e61351 100755 --- a/tests/common/test_case.rs +++ b/tests/common/test_case.rs @@ -74,7 +74,7 @@ impl TestCase { impl TestPokemon { fn to_pokemon(&self, library: Arc) -> Pokemon { - let mut builder = PokemonBuilder::new(library, StringKey::new(self.species.as_str()), self.level); + let mut builder = PokemonBuilder::new(library, StringKey::new(self.species.as_str().into()), self.level); for move_name in &self.moves { builder = builder.learn_move(StringKey::new(move_name)); } diff --git a/tests/data/gen7_scripts.wasm b/tests/data/gen7_scripts.wasm index 2e9857b..e183ff8 100755 Binary files a/tests/data/gen7_scripts.wasm and b/tests/data/gen7_scripts.wasm differ diff --git a/tests/main.rs b/tests/main.rs index a48dc5a..e0314fa 100755 --- a/tests/main.rs +++ b/tests/main.rs @@ -7,8 +7,6 @@ use std::io::Read; use std::path::Path; use std::sync::Arc; -use conquer_once::OnceCell; - use pkmn_lib::dynamic_data::{ Battle, BattleParty, DamageSource, DynamicLibrary, ExecutingMove, MoveChoice, PokemonBuilder, PokemonParty, Script, ScriptCategory, ScriptContainer, ScriptOwnerData, TurnChoice, VolatileScriptsOwner, @@ -19,22 +17,11 @@ use crate::common::{library_loader, TestCase}; pub mod common; -static LIBRARY: OnceCell> = OnceCell::uninit(); - fn get_library() -> Arc { - LIBRARY - .get_or_init(|| { - let start_time = chrono::Utc::now(); - let lib = library_loader::load_library(); - let end_time = chrono::Utc::now(); - println!("Built library in {} ms", (end_time - start_time).num_milliseconds()); - Arc::new(lib) - }) - .clone() + Arc::new(library_loader::load_library()) } #[test] -#[cfg_attr(miri, ignore)] fn validate_library_load() { let start_time = chrono::Utc::now(); library_loader::load_library(); diff --git a/valgrind_suppr b/valgrind_suppr new file mode 100644 index 0000000..d63c5ee --- /dev/null +++ b/valgrind_suppr @@ -0,0 +1,90 @@ +{ + + Memcheck:Leak + fun:malloc + fun:alloc + fun:__rdl_alloc + fun:_ZN5alloc5alloc5alloc17hc42e909f81160460E + fun:_ZN96_$LT$hashbrown..raw..alloc..inner..Global$u20$as$u20$hashbrown..raw..alloc..inner..Allocator$GT$8allocate17h2c481e4442c55c5dE + fun:_ZN9hashbrown3raw5alloc5inner8do_alloc17h1f83bdd1222cbbb7E + fun:_ZN9hashbrown3raw22RawTableInner$LT$A$GT$17new_uninitialized17h12dbb4fa91b4b3afE + fun:_ZN9hashbrown3raw22RawTableInner$LT$A$GT$22fallible_with_capacity17h6df80e2764604857E + fun:_ZN9hashbrown3raw22RawTableInner$LT$A$GT$14prepare_resize17h71d20d4d23776238E + fun:_ZN9hashbrown3raw21RawTable$LT$T$C$A$GT$14reserve_rehash17h28974fc9c4c277e6E.llvm.15230268944078492848 + fun:_ZN9hashbrown3raw21RawTable$LT$T$C$A$GT$7reserve17h7eee95820260d1e7E.llvm.15230268944078492848 + fun:_ZN9hashbrown3raw21RawTable$LT$T$C$A$GT$6insert17h35ff9588f93ce06cE + fun:_ZN9hashbrown3map28HashMap$LT$K$C$V$C$S$C$A$GT$6insert17h996ff1a9e535e422E +} + +{ + + Memcheck:Leak + fun:malloc + fun:alloc + fun:__rdl_alloc + fun:_ZN5alloc5alloc6Global10alloc_impl17hd6fbb6e351b4be39E.llvm.18227935767307273530 + fun:allocate + fun:_ZN5alloc5alloc15exchange_malloc17h9e4cc8ad48821a81E + fun:new<[[u64; 4]; 2]> + fun:_ZN94_$LT$ahash..random_state..DefaultRandomSource$u20$as$u20$ahash..random_state..RandomSource$GT$15get_fixed_seeds28_$u7b$$u7b$closure$u7d$$u7d$17h1797bff870f50682E + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$11get_or_init28_$u7b$$u7b$closure$u7d$$u7d$17h744caffedf4c7067E + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$15get_or_try_init17hcd2c841e12e37bc0E + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$11get_or_init17h7d3ca5ccc71b3021E + fun:_ZN94_$LT$ahash..random_state..DefaultRandomSource$u20$as$u20$ahash..random_state..RandomSource$GT$15get_fixed_seeds17h2a6c6672bd2f8f7bE + fun:_ZN5ahash12random_state11RandomState3new17he4bd97026fbf5adcE.llvm.11960766389962301245 + fun:_ZN75_$LT$ahash..random_state..RandomState$u20$as$u20$core..default..Default$GT$7default17h65efd61ef64a7f0dE + fun:_ZN87_$LT$hashbrown..map..HashMap$LT$K$C$V$C$S$C$A$GT$$u20$as$u20$core..default..Default$GT$7default17h40e688f79e703e93E.llvm.35124437821632695 +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:alloc + fun:__rdl_alloc + fun:_ZN5alloc5alloc6Global10alloc_impl17h0263a87402431af1E.llvm.1186731428384934186 + fun:allocate + fun:_ZN5alloc5alloc15exchange_malloc17h2285591b899cc9f4E + fun:new> + fun:_ZN5ahash12random_state11RandomState7get_src28_$u7b$$u7b$closure$u7d$$u7d$17h5cf982d28005fdddE + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$11get_or_init28_$u7b$$u7b$closure$u7d$$u7d$17h72179437b77bfeebE + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$15get_or_try_init17h4373eb8bae30d42dE.llvm.10117491539980278462 + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$11get_or_init17hec6279877245cea1E + fun:_ZN5ahash12random_state11RandomState7get_src17haf7fc09e2535a0a7E.llvm.11960766389962301245 + fun:_ZN5ahash12random_state11RandomState3new17he4bd97026fbf5adcE.llvm.11960766389962301245 + fun:_ZN75_$LT$ahash..random_state..RandomState$u20$as$u20$core..default..Default$GT$7default17h65efd61ef64a7f0dE + fun:_ZN87_$LT$hashbrown..map..HashMap$LT$K$C$V$C$S$C$A$GT$$u20$as$u20$core..default..Default$GT$7default17h40e688f79e703e93E.llvm.35124437821632695 +} + +{ + + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:alloc + fun:__rdl_alloc + fun:_ZN5alloc5alloc6Global10alloc_impl17h0263a87402431af1E.llvm.1186731428384934186 + fun:allocate + fun:_ZN5alloc5alloc15exchange_malloc17h2285591b899cc9f4E + fun:new + fun:_ZN5ahash12random_state11RandomState7get_src28_$u7b$$u7b$closure$u7d$$u7d$17h5cf982d28005fdddE + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$11get_or_init28_$u7b$$u7b$closure$u7d$$u7d$17h72179437b77bfeebE + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$15get_or_try_init17h4373eb8bae30d42dE.llvm.10117491539980278462 + fun:_ZN9once_cell4race8once_box16OnceBox$LT$T$GT$11get_or_init17hec6279877245cea1E + fun:_ZN5ahash12random_state11RandomState7get_src17haf7fc09e2535a0a7E.llvm.11960766389962301245 + fun:_ZN5ahash12random_state11RandomState3new17he4bd97026fbf5adcE.llvm.11960766389962301245 + fun:_ZN75_$LT$ahash..random_state..RandomState$u20$as$u20$core..default..Default$GT$7default17h65efd61ef64a7f0dE + fun:_ZN9hashbrown3map20HashMap$LT$K$C$V$GT$13with_capacity17h8042103d2e19cc61E +} + +{ + + Memcheck:Leak + fun:malloc + fun:alloc + fun:__rdl_alloc + fun:_ZN5alloc5alloc5alloc17hdc225bf5a9332839E + fun:_ZN6arcstr7arc_str9ThinInner12try_allocate17h5ec0d22c686b0aa1E + fun:_ZN6arcstr7arc_str9ThinInner8allocate17hb1fd6d38fd1e7864E +}