dyon/
link.rs

1use std::fmt;
2use std::sync::Arc;
3
4use crate::Variable;
5
6// Do not change this without updating the algorithms!
7const BLOCK_SIZE: usize = 124;
8
9const EMPTY: u64 = 0x0;
10const BOOL: u64 = 0x1;
11const F64: u64 = 0x2;
12const STR: u64 = 0x3;
13
14/// Stores link memory in chunks of 1024 bytes.
15pub struct Block {
16    data: [u64; BLOCK_SIZE],
17    tys: [u64; 4],
18}
19
20impl Block {
21    fn new() -> Block {
22        Block {
23            data: [0; BLOCK_SIZE],
24            tys: [0; 4],
25        }
26    }
27
28    pub(crate) fn var(&self, ind: u8) -> Variable {
29        use std::mem::transmute;
30
31        let k = ind as usize;
32        assert!(k < BLOCK_SIZE);
33        let i = k / 32;
34        let j = k - i * 32;
35        match self.tys[i] >> (j * 2) & 0x3 {
36            EMPTY => panic!("Reading beyond end"),
37            BOOL => Variable::bool(self.data[k] != 0),
38            F64 => Variable::f64(f64::from_bits(self.data[k])),
39            STR => Variable::Str(unsafe { transmute::<&u64, &Arc<String>>(&self.data[k]) }.clone()),
40            _ => panic!("Invalid type"),
41        }
42    }
43
44    fn push(&mut self, var: &Variable, pos: usize) {
45        use std::mem::transmute;
46
47        let k = pos;
48        assert!(k < BLOCK_SIZE);
49
50        let i = k / 32;
51        let j = k - i * 32;
52        match *var {
53            Variable::Bool(val, _) => {
54                // Reset bits.
55                self.tys[i] &= !(0x3 << (j * 2));
56                // Sets new bits.
57                self.tys[i] |= BOOL << (j * 2);
58                self.data[k] = val as u64;
59            }
60            Variable::F64(val, _) => {
61                // Reset bits.
62                self.tys[i] &= !(0x3 << (j * 2));
63                // Sets new bits.
64                self.tys[i] |= F64 << (j * 2);
65                self.data[k] = val.to_bits();
66            }
67            Variable::Str(ref s) => {
68                // Reset bits.
69                self.tys[i] &= !(0x3 << (j * 2));
70                // Sets new bits.
71                self.tys[i] |= STR << (j * 2);
72                self.data[k] = unsafe { transmute::<Arc<String>, usize>(s.clone()) as u64 };
73            }
74            _ => panic!("Expected `str`, `f64`, `bool`"),
75        }
76    }
77}
78
79impl Clone for Block {
80    fn clone(&self) -> Block {
81        use std::mem::transmute;
82
83        let mut data = self.data;
84        for k in 0..BLOCK_SIZE {
85            let i = k / 32;
86            let j = k - i * 32;
87            match self.tys[i] >> (j * 2) & 0x3 {
88                EMPTY => break,
89                STR => {
90                    // Arc<String>
91                    unsafe {
92                        data[k] = transmute::<Arc<String>, usize>(
93                            transmute::<&usize, &Arc<String>>(&(self.data[k] as usize)).clone(),
94                        ) as u64;
95                    }
96                }
97                _ => {}
98            }
99        }
100        Block {
101            data,
102            tys: self.tys,
103        }
104    }
105}
106
107impl Drop for Block {
108    fn drop(&mut self) {
109        use std::mem::transmute;
110
111        for k in 0..BLOCK_SIZE {
112            let i = k / 32;
113            let j = k - i * 32;
114            match self.tys[i] >> (j * 2) & 0x3 {
115                EMPTY => break,
116                STR => {
117                    // Arc<String>
118                    unsafe { drop(transmute::<usize, Arc<String>>(self.data[k] as usize)) }
119                }
120                _ => {}
121            }
122        }
123    }
124}
125
126impl fmt::Debug for Block {
127    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
128        write!(f, "Block")
129    }
130}
131
132#[derive(Debug, Clone)]
133pub(crate) struct Slice {
134    pub(crate) block: Arc<Block>,
135    pub(crate) start: u8,
136    pub(crate) end: u8,
137}
138
139impl Slice {
140    fn new() -> Slice {
141        Slice {
142            block: Arc::new(Block::new()),
143            start: 0,
144            end: 0,
145        }
146    }
147}
148
149/// Stores a link structure.
150#[derive(Debug, Clone)]
151pub struct Link {
152    pub(crate) slices: Vec<Slice>,
153}
154
155impl Default for Link {
156    fn default() -> Link {
157        Link::new()
158    }
159}
160
161impl Link {
162    /// Creates a new link.
163    pub fn new() -> Link {
164        Link { slices: vec![] }
165    }
166
167    /// Gets the first item of the link.
168    pub fn head(&self) -> Option<Box<Variable>> {
169        if self.slices.is_empty() {
170            None
171        } else {
172            let first = &self.slices[0];
173            if first.start < first.end {
174                Some(Box::new(first.block.var(first.start)))
175            } else {
176                None
177            }
178        }
179    }
180
181    /// Gets the last item of the link.
182    pub fn tip(&self) -> Option<Box<Variable>> {
183        if let Some(last) = self.slices.last() {
184            if last.start < last.end {
185                Some(Box::new(last.block.var(last.end - 1)))
186            } else {
187                None
188            }
189        } else {
190            None
191        }
192    }
193
194    /// Gets the tail of the link.
195    ///
196    /// The tail is the whole link except the first item.
197    pub fn tail(&self) -> Link {
198        if self.slices.is_empty() {
199            Link::new()
200        } else {
201            let first = &self.slices[0];
202            let mut l = Link::new();
203            // No danger of overflow since `BLOCK_SIZE = 124`.
204            if first.start + 1 < first.end {
205                l.slices.push(first.clone());
206                l.slices[0].start += 1;
207            }
208            for slice in self.slices.iter().skip(1) {
209                l.slices.push(slice.clone())
210            }
211            l
212        }
213    }
214
215    /// Gets the neck of the link.
216    ///
217    /// The neck is the whole link except the last item.
218    pub fn neck(&self) -> Link {
219        if let Some(last) = self.slices.last() {
220            let mut l = Link::new();
221            for slice in self.slices.iter().take(self.slices.len() - 1) {
222                l.slices.push(slice.clone())
223            }
224            // No danger of overflow since `BLOCK_SIZE = 124`.
225            if last.start + 1 < last.end {
226                l.slices.push(Slice {
227                    block: last.block.clone(),
228                    start: last.start,
229                    end: last.end - 1,
230                })
231            }
232            l
233        } else {
234            Link::new()
235        }
236    }
237
238    /// Returns `true` if the link is empty.
239    pub fn is_empty(&self) -> bool {
240        self.slices.len() == 0
241    }
242
243    /// Adds another link.
244    pub fn add(&self, other: &Link) -> Link {
245        let mut slices = Vec::with_capacity(self.slices.len() + other.slices.len());
246        slices.extend_from_slice(&self.slices);
247        slices.extend_from_slice(&other.slices);
248        Link { slices }
249    }
250
251    /// Pushes a variable to the link.
252    pub fn push(&mut self, v: &Variable) -> Result<(), String> {
253        use crate::Variable::*;
254
255        match *v {
256            Bool(_, _) | F64(_, _) | Str(_) => {
257                if !self.slices.is_empty() {
258                    let last = self.slices.last_mut().unwrap();
259                    if (last.end as usize) < BLOCK_SIZE {
260                        Arc::make_mut(&mut last.block).push(v, last.end as usize);
261                        last.end += 1;
262                        return Ok(());
263                    }
264                }
265
266                self.slices.push(Slice::new());
267                let last = self.slices.last_mut().unwrap();
268                Arc::make_mut(&mut last.block).push(v, 0);
269                last.end = 1;
270                Ok(())
271            }
272            Link(ref link) => {
273                for slice in &link.slices {
274                    for i in slice.start..slice.end {
275                        self.push(&slice.block.var(i))?
276                    }
277                }
278                Ok(())
279            }
280            _ => Err("Expected `bool`, `f64` or `str`".into()),
281        }
282    }
283}