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}