Skip to main content

competitive/tools/
associated_value.rs

1/// Trait for a modifiable value associated with a type.
2pub trait AssociatedValue {
3    /// Type of value.
4    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/// Implement [`AssociatedValue`].
35///
36/// [`AssociatedValue`]: super::AssociatedValue
37///
38/// # Examples
39///
40/// ```
41/// use competitive::tools::AssociatedValue;
42/// enum X {}
43/// competitive::impl_assoc_value!(X, usize, 1);
44/// assert_eq!(X::get(), 1);
45/// X::set(10);
46/// assert_eq!(X::get(), 10);
47/// ```
48///
49/// init with `Default::default()`
50///
51/// ```
52/// use competitive::tools::AssociatedValue;
53/// enum X {}
54/// competitive::impl_assoc_value!(X, usize);
55/// assert_eq!(X::get(), Default::default());
56/// ```
57#[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::tools::Xorshift;
78
79    #[test]
80    fn test_associated_value() {
81        enum X {}
82        impl_assoc_value!(X, usize);
83        let mut rng = Xorshift::default();
84        let mut expected = 0usize;
85        for _ in 0..1000 {
86            let value = rng.random(..);
87            match rng.random(0..3) {
88                0 => {
89                    X::set(value);
90                    expected = value;
91                }
92                1 => {
93                    assert_eq!(X::replace(value), expected);
94                    expected = value;
95                }
96                _ => {
97                    X::modify(|x| *x ^= value);
98                    expected ^= value;
99                }
100            }
101            assert_eq!(X::get(), expected);
102            assert_eq!(X::with(|x| x.count_ones()), expected.count_ones());
103        }
104    }
105}