competitive/tools/
associated_value.rs1pub trait AssociatedValue {
3 type T: 'static + Clone;
5 unsafe fn __local_key() -> &'static std::thread::LocalKey<std::cell::Cell<Self::T>>;
6 #[inline]
7 fn get() -> Self::T {
8 Self::with(Clone::clone)
9 }
10 #[inline]
11 fn set(x: Self::T) {
12 unsafe { Self::__local_key().with(|cell| cell.set(x)) }
13 }
14 #[inline]
15 fn replace(x: Self::T) -> Self::T {
16 unsafe { Self::__local_key().with(|cell| cell.replace(x)) }
17 }
18 #[inline]
19 fn with<F, R>(f: F) -> R
20 where
21 F: FnOnce(&Self::T) -> R,
22 {
23 unsafe { Self::__local_key().with(|cell| f(&*cell.as_ptr())) }
24 }
25 #[inline]
26 fn modify<F, R>(f: F) -> R
27 where
28 F: FnOnce(&mut Self::T) -> R,
29 {
30 unsafe { Self::__local_key().with(|cell| f(&mut *cell.as_ptr())) }
31 }
32}
33
34#[macro_export]
58macro_rules! impl_assoc_value {
59 ($name:ident, $t:ty) => {
60 $crate::impl_assoc_value!($name, $t, Default::default());
61 };
62 ($name:ident, $t:ty, $e:expr) => {
63 impl AssociatedValue for $name {
64 type T = $t;
65 #[inline]
66 unsafe fn __local_key() -> &'static ::std::thread::LocalKey<::std::cell::Cell<Self::T>> {
67 ::std::thread_local!(static __LOCAL_KEY: ::std::cell::Cell<$t> = ::std::cell::Cell::new($e));
68 &__LOCAL_KEY
69 }
70 }
71 };
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77 use crate::impl_assoc_value;
78
79 #[test]
80 fn test_associated_value() {
81 enum X {}
82 impl_assoc_value!(X, usize);
83 X::set(10);
84 assert_eq!(X::get(), 10);
85 assert_eq!(X::with(|x| x + 1), 11);
86 X::modify(|x| *x += 1);
87 assert_eq!(X::get(), 11);
88 }
89}