sb_rust_library/update_buffer.rs
1/// Data structure which uses a buffer to perform buffered updates to data.
2///
3/// Explicitly, this structure keeps two copies of some generic data type, which
4/// can be accesssed by the methods `old()` and `new()`. The idea is that during
5/// the course of an algorithm, you read from the `old` values and write to the
6/// `new` values. Then after the step is finished, you call `swap_buffer` such
7/// that `old` now points towards `new`.
8///
9/// Since you read from `old` and write to `new`, the methods `old()` and
10/// `new()` return `&T` and `&mut T` respectively. This prevents any borrowing
11/// conflicts.
12///
13/// This data structure provides three main benefits:
14/// 1. It makes the update step in an algorithm clean and explicit.
15/// 2. It allocates all memory used at initialization so the algorithm doesn't
16/// have to allocate memory in each step.
17/// 3. It plays well with the rust borrow checker.
18///
19pub struct UpdateBuffer<T: Sized + Clone> {
20 buffers: [T; 2],
21 old_index: usize,
22 new_index: usize,
23}
24
25impl<T: Sized + Clone> UpdateBuffer<T> {
26
27 /// Creates a new update buffer with the given data written to the old and new buffers.
28 pub fn from(initial: T) -> UpdateBuffer<T> {
29 UpdateBuffer {
30 buffers: [initial.clone(), initial],
31 old_index: 0,
32 new_index: 1,
33 }
34 }
35
36 /// Get mutable access to the new values in the buffer.
37 pub fn new(&mut self) -> &mut T {
38 &mut self.buffers[self.new_index]
39 }
40
41 /// Get immutable access to the old values in the buffer.
42 pub fn old(&self) -> &T {
43 &self.buffers[self.old_index]
44 }
45
46 /// Swap the new and the old buffers (i.e. set the new updated data to be the old data).
47 pub fn swap_buffers(&mut self) {
48 if self.old_index == 1 {
49 self.old_index = 0;
50 self.new_index = 1;
51 } else {
52 self.old_index = 1;
53 self.new_index = 0;
54 }
55 }
56}