Last active
December 30, 2019 02:38
-
-
Save stepancheg/341a7b81d57a92808f7295a8acef6203 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Sample `lazy_static` function which provides an utility | |
//! similar to [lazy_static crate](https://github.com/rust-lang-nursery/lazy-static.rs) | |
//! but without any macros. | |
#![feature(alloc_static)] | |
use std::ptr; | |
use std::collections::HashMap; | |
use std::sync::atomic::*; | |
/// The function creates a pointer to a variable of type `T` | |
/// initialized with the provided callback. | |
/// | |
/// Note this function returns previously initialized value pointer | |
/// on subseqent invocations. | |
/// | |
/// Note this function uses a function type as a key, so | |
/// returned values are: | |
/// * different for different function types | |
/// * but the same if function type is the same, but behaves differently | |
pub fn lazy_static<T: Sync + 'static, F: FnOnce() -> T + 'static>(init: F) -> &'static T { | |
struct LazyStaticHolder<T> { | |
init: AtomicU8, | |
t: T, | |
} | |
unsafe { | |
let holder = &mut *::std::alloc::alloc_static::<F, LazyStaticHolder<T>>(); | |
loop { | |
if holder.init.load(Ordering::SeqCst) == 2 { | |
return &holder.t; | |
} | |
if let Ok(_) = holder.init.compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst) { | |
ptr::write(&mut holder.t as *mut T, init()); | |
holder.init.store(2, Ordering::SeqCst); | |
return &holder.t; | |
} | |
} | |
} | |
} | |
fn get_hashmap() -> &'static HashMap<u32, &'static str> { | |
lazy_static(|| { | |
let mut m = HashMap::new(); | |
m.insert(0, "foo"); | |
m.insert(1, "bar"); | |
m.insert(2, "baz"); | |
m | |
}) | |
} | |
// This function returns a different map than `get_hashmap` because | |
// `lazy_static` invocation is parameterized by a different function. | |
fn get_another_hashmap() -> &'static HashMap<u32, &'static str> { | |
lazy_static(|| { | |
let mut m = HashMap::new(); | |
m.insert(0, "one"); | |
m.insert(1, "two"); | |
m.insert(2, "three"); | |
m | |
}) | |
} | |
fn main() { | |
// First access to `HASHMAP` initializes it | |
println!("The entry for `0` is \"{}\".", get_hashmap().get(&0).unwrap()); | |
// Any further access to `HASHMAP` just returns the computed value | |
println!("The entry for `1` is \"{}\".", get_hashmap().get(&1).unwrap()); | |
// Although map types are the same, map objects are different | |
println!("The entry for `0` from another map is \"{}\".", get_another_hashmap().get(&0).unwrap()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment