MPD  0.20.6
ForeignFifoBuffer.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2014 Max Kellermann <max.kellermann@gmail.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20  * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef FOREIGN_FIFO_BUFFER_HXX
31 #define FOREIGN_FIFO_BUFFER_HXX
32 
33 #include "WritableBuffer.hxx"
34 
35 #include <utility>
36 #include <algorithm>
37 
38 #include <cstddef>
39 
40 #include <assert.h>
41 
51 template<typename T>
53 public:
54  typedef size_t size_type;
58 
59 protected:
60  size_type head, tail, capacity;
61  T *data;
62 
63 public:
64  explicit constexpr ForeignFifoBuffer(std::nullptr_t n)
65  :head(0), tail(0), capacity(0), data(n) {}
66 
67  constexpr ForeignFifoBuffer(T *_data, size_type _capacity)
68  :head(0), tail(0), capacity(_capacity), data(_data) {}
69 
71  :head(src.head), tail(src.tail),
72  capacity(src.capacity), data(src.data) {
73  src.SetNull();
74  }
75 
77  head = src.head;
78  tail = src.tail;
79  capacity = src.capacity;
80  data = src.data;
81  src.SetNull();
82  return *this;
83  }
84 
85  void Swap(ForeignFifoBuffer<T> &other) {
86  std::swap(head, other.head);
87  std::swap(tail, other.tail);
88  std::swap(capacity, other.capacity);
89  std::swap(data, other.data);
90  }
91 
92  constexpr bool IsNull() const {
93  return data == nullptr;
94  }
95 
96  constexpr bool IsDefined() const {
97  return !IsNull();
98  }
99 
100  T *GetBuffer() {
101  return data;
102  }
103 
104  constexpr size_type GetCapacity() const {
105  return capacity;
106  }
107 
108  void SetNull() {
109  head = tail = 0;
110  capacity = 0;
111  data = nullptr;
112  }
113 
114  void SetBuffer(T *_data, size_type _capacity) {
115  assert(_data != nullptr);
116  assert(_capacity > 0);
117 
118  head = tail = 0;
119  capacity = _capacity;
120  data = _data;
121  }
122 
123  void MoveBuffer(T *new_data, size_type new_capacity) {
124  assert(new_capacity >= tail - head);
125 
126  std::move(data + head, data + tail, new_data);
127  data = new_data;
128  capacity = new_capacity;
129  tail -= head;
130  head = 0;
131  }
132 
133  void Clear() {
134  head = tail = 0;
135  }
136 
137  constexpr bool IsEmpty() const {
138  return head == tail;
139  }
140 
141  constexpr bool IsFull() const {
142  return head == 0 && tail == capacity;
143  }
144 
149  Range Write() {
150  if (IsEmpty())
151  Clear();
152  else if (tail == capacity)
153  Shift();
154 
155  return Range(data + tail, capacity - tail);
156  }
157 
158  bool WantWrite(size_type n) {
159  if (tail + n <= capacity)
160  /* enough space after the tail */
161  return true;
162 
163  const size_type in_use = tail - head;
164  const size_type required_capacity = in_use + n;
165  if (required_capacity > capacity)
166  return false;
167 
168  Shift();
169  assert(tail + n <= capacity);
170  return true;
171  }
172 
177  void Append(size_type n) {
178  assert(tail <= capacity);
179  assert(n <= capacity);
180  assert(tail + n <= capacity);
181 
182  tail += n;
183  }
184 
185  constexpr size_type GetAvailable() const {
186  return tail - head;
187  }
188 
193  constexpr Range Read() const {
194  return Range(data + head, tail - head);
195  }
196 
200  void Consume(size_type n) {
201  assert(tail <= capacity);
202  assert(head <= tail);
203  assert(n <= tail);
204  assert(head + n <= tail);
205 
206  head += n;
207  }
208 
209  size_type Read(pointer_type p, size_type n) {
210  auto range = Read();
211  if (n > range.size)
212  n = range.size;
213  std::copy_n(range.data, n, p);
214  Consume(n);
215  return n;
216  }
217 
223  size_type MoveFrom(ForeignFifoBuffer<T> &src) {
224  auto r = src.Read();
225  auto w = Write();
226  size_t n = std::min(r.size, w.size);
227 
228  std::move(r.data, r.data + n, w.data);
229  Append(n);
230  src.Consume(n);
231  return n;
232  }
233 
234 protected:
235  void Shift() {
236  if (head == 0)
237  return;
238 
239  assert(head <= capacity);
240  assert(tail <= capacity);
241  assert(tail >= head);
242 
243  std::move(data + head, data + tail, data);
244 
245  tail -= head;
246  head = 0;
247  }
248 };
249 
250 #endif
void Swap(ForeignFifoBuffer< T > &other)
ForeignFifoBuffer(ForeignFifoBuffer &&src)
void MoveBuffer(T *new_data, size_type new_capacity)
size_type Read(pointer_type p, size_type n)
constexpr ForeignFifoBuffer(std::nullptr_t n)
Range::pointer_type pointer_type
A reference to a memory area that is writable.
Definition: Silence.hxx:27
bool WantWrite(size_type n)
void Consume(size_type n)
Marks a chunk as consumed.
constexpr bool IsEmpty() const
constexpr bool IsNull() const
constexpr size_type GetAvailable() const
constexpr bool IsFull() const
ForeignFifoBuffer & operator=(ForeignFifoBuffer &&src)
Range::const_pointer_type const_pointer_type
constexpr size_type GetCapacity() const
Range Write()
Prepares writing.
A first-in-first-out buffer: you can append data at the end, and read data from the beginning...
constexpr bool IsDefined() const
void SetBuffer(T *_data, size_type _capacity)
constexpr Range Read() const
Return a buffer range which may be read.
constexpr ForeignFifoBuffer(T *_data, size_type _capacity)
void Append(size_type n)
Expands the tail of the buffer, after data has been written to the buffer returned by write()...
size_type MoveFrom(ForeignFifoBuffer< T > &src)
Move as much data as possible from the specified buffer.
const T * const_pointer_type
WritableBuffer< T > Range