1 /******************************************************************************* 2 3 Contains a ring buffer implementation with fixed size 4 5 Copyright: 6 Copyright (c) 2020 BOS Platform Foundation Korea 7 All rights reserved. 8 9 License: 10 MIT License. See LICENSE for details. 11 12 *******************************************************************************/ 13 14 module geod24.RingBuffer; 15 16 import std.range; 17 18 /******************************************************************************* 19 20 A ring buffer with fixed size 21 22 Params: 23 T = Type of elements 24 25 *******************************************************************************/ 26 27 public class RingBuffer (T) 28 { 29 /******************************************************************************* 30 31 Params: 32 size = Maximum number of elements, must be greater than 0 33 34 *******************************************************************************/ 35 36 this (size_t size) @safe pure nothrow 37 { 38 assert(size, "Cannot create a RingBuffer with size of 0"); 39 this.storage.length = size; 40 this.write_range = cycle(this.storage[]); 41 this.read_range = cycle(this.storage[]); 42 } 43 44 /// Returns: true if full 45 public bool full () @safe @nogc pure nothrow 46 { 47 return this.len == this.storage.length; 48 } 49 50 /// Returns: true if empty 51 public bool empty () @safe @nogc pure nothrow 52 { 53 return this.len == 0; 54 } 55 56 /// Returns: Number of elements currently in the buffer 57 public size_t length () @safe @nogc pure nothrow 58 { 59 return this.len; 60 } 61 62 /******************************************************************************* 63 64 Insert an element to the buffer 65 66 Params: 67 val = an element of type T 68 69 *******************************************************************************/ 70 71 public void insert () (auto ref T val) @safe @nogc pure nothrow 72 { 73 assert(!this.full(), "Attempting to insert to a full RingBuffer"); 74 75 write_range.front() = val; 76 write_range.popFront(); 77 this.len++; 78 } 79 80 /// Returns: Element in the front of the buffer 81 public T front () @safe @nogc pure nothrow 82 { 83 assert(!this.empty(), "Attempting to read from a full RingBuffer"); 84 return read_range.front(); 85 } 86 87 /// Removes the element in the front of the buffer 88 public void popFront () @safe @nogc pure nothrow 89 { 90 assert(!this.empty(), "Attempting to pop from a full RingBuffer"); 91 this.len--; 92 read_range.popFront(); 93 } 94 95 /// Current number of elements 96 private size_t len; 97 98 /// Underlying storage 99 private T[] storage; 100 101 /// Cyclic range for writes 102 private Cycle!(T[]) write_range; 103 104 /// Cyclic range for reads 105 private Cycle!(T[]) read_range; 106 } 107 108 unittest 109 { 110 import std.stdio; 111 const buffer_size = 3; 112 auto buffer = new RingBuffer!int(buffer_size); 113 114 foreach (_; 0..2) 115 { 116 assert(buffer.empty()); 117 assert(!buffer.full()); 118 119 foreach (i; 0..buffer_size) 120 { 121 assert(!buffer.full()); 122 buffer.insert(i); 123 assert(!buffer.empty()); 124 assert(buffer.length == i + 1); 125 } 126 assert(buffer.full()); 127 128 foreach (i; 0..buffer_size) 129 { 130 assert(!buffer.empty()); 131 assert(buffer.front() == i); 132 buffer.popFront(); 133 } 134 } 135 }