Roc Toolkit internal modules
Roc Toolkit: real-time audio streaming
slice.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Roc Streaming authors
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7  */
8 
9 //! @file roc_core/slice.h
10 //! @brief Slice.
11 
12 #ifndef ROC_CORE_SLICE_H_
13 #define ROC_CORE_SLICE_H_
14 
15 #include "roc_core/buffer.h"
16 #include "roc_core/print_memory.h"
17 #include "roc_core/shared_ptr.h"
18 
19 namespace roc {
20 namespace core {
21 
22 //! Slice.
23 //!
24 //! Slice points to a subrange of data in pool-allocated Buffer.
25 //! Copying a slice produces a new slice referring the same data.
26 //!
27 //! Slice also acts as a kind of shared pointer to Buffer. A buffer won't be freed
28 //! (returned to pool) until there are slices referring it. Copying a slice
29 //! increments the buffer reference counter, and destroying a slice decrements it.
30 //!
31 //! While Buffer works with raw bytes, Slice<T> interprets it as array of elements
32 //! of type T, and works in terms of those elements.
33 //!
34 //! Slice has two important characteristics:
35 //! - size - the difference between the ending end beginning pointer
36 //! - capacity - the difference between the actual buffer end and the
37 //! slice beginning pointer
38 //!
39 //! Buffers are not resizable. They're allocated from pool and have fixed size,
40 //! defined by the pool parameters.
41 //!
42 //! Slices are reslicable, which means that their pointers to the buffer data
43 //! may be moved within the buffer.
44 //!
45 //! The beginning pointer may be moved only forward. Once moved, it's not allowed
46 //! to move it backward again. Moving it decreases the slice size and capacity.
47 //! Capacity is affected because it's relative to the beginning pointer.
48 //!
49 //! The ending pointer may be freely moved forward and backward within the slice
50 //! capacity. Moving it affects the slice size, but not capacity.
51 //!
52 //! In other words, slice capacity may be only decreased by moving beginning pointer,
53 //! and slice size may be freely changed within the slice capacity by moving both
54 //! beginning and ending pointers.
55 template <class T> class Slice {
56 public:
57  //! Construct empty slice.
59  : buffer_()
60  , data_(NULL)
61  , size_(0) {
62  }
63 
64  //! Construct slice pointing to the whole buffer.
65  Slice(const BufferPtr& buffer) {
66  buffer_ = buffer;
67  if (buffer_) {
68  data_ = (T*)buffer->data();
69  size_ = buffer->size() / sizeof(T);
70  } else {
71  data_ = NULL;
72  size_ = 0;
73  }
74  }
75 
76  //! Construct slice pointing to a part of a buffer.
77  Slice(Buffer& buffer, size_t from, size_t to) {
78  if (from > to) {
79  roc_panic("slice: invalid range: [%lu,%lu)", (unsigned long)from,
80  (unsigned long)to);
81  }
82  if (to > buffer.size() / sizeof(T)) {
83  roc_panic("slice: out of bounds: available=[%lu,%lu) requested=[%lu,%lu)",
84  (unsigned long)0, (unsigned long)buffer.size() / sizeof(T),
85  (unsigned long)from, (unsigned long)to);
86  }
87  buffer_ = &buffer;
88  data_ = (T*)buffer.data() + from;
89  size_ = to - from;
90  }
91 
92  //! Get slice data.
93  T* data() const {
94  if (data_ == NULL) {
95  roc_panic("slice: null slice");
96  }
97  return data_;
98  }
99 
100  //! Pointer to the next after the last element in slice.
101  T* data_end() const {
102  if (data_ == NULL) {
103  roc_panic("slice: null slice");
104  }
105  return data_ + size_;
106  }
107 
108  //! Get number of elements in slice.
109  size_t size() const {
110  return size_;
111  }
112 
113  //! Get maximum possible number of elements in slice.
114  size_t capacity() const {
115  if (data_ == NULL) {
116  return 0;
117  } else {
118  return buffer_->size() / sizeof(T) - size_t(data_ - (T*)buffer_->data());
119  }
120  }
121 
122  //! Change slice beginning and ending inside the buffer.
123  //! @remarks
124  //! - @p from and @p to are relative to slice beginning.
125  //! - @p to value can be up to capacity().
126  void reslice(size_t from, size_t to) {
127  const size_t cap = capacity();
128  if (from > to) {
129  roc_panic("slice: invalid range: [%lu,%lu)", (unsigned long)from,
130  (unsigned long)to);
131  }
132  if (to > cap) {
133  roc_panic("slice: out of bounds: available=[%lu,%lu) requested=[%lu,%lu)",
134  (unsigned long)0, (unsigned long)cap, (unsigned long)from,
135  (unsigned long)to);
136  }
137  if (data_) {
138  data_ = data_ + from;
139  size_ = to - from;
140  }
141  }
142 
143  //! Increase size() by @p add_sz.
144  //! @returns
145  //! Pointer to the first element of extended range.
146  T* extend(const size_t add_sz) {
147  if (data_ == NULL) {
148  roc_panic("slice: null slice");
149  }
150  if (add_sz == 0) {
151  roc_panic("slice: extend with zero size");
152  }
153  T* ret = data_ + size_;
154  reslice(0, size() + add_sz);
155  return ret;
156  }
157 
158  //! Construct a slice pointing to a part of this slice.
159  //! @remarks
160  //! - @p from and @p to are relative to slice beginning.
161  //! - @p to value can be up to size().
162  Slice subslice(size_t from, size_t to) const {
163  if (from > to) {
164  roc_panic("slice: invalid range: [%lu,%lu)", (unsigned long)from,
165  (unsigned long)to);
166  }
167  if (to > size_) {
168  roc_panic("slice: out of bounds: available=[%lu,%lu) requested=[%lu,%lu)",
169  (unsigned long)0, (unsigned long)size_, (unsigned long)from,
170  (unsigned long)to);
171  }
172  Slice ret;
173  ret.buffer_ = buffer_;
174  ret.data_ = data_ + from;
175  ret.size_ = to - from;
176  return ret;
177  }
178 
179  //! Print slice to stderr.
180  void print() const {
181  if (buffer_) {
182  core::print_memory_slice(data_, size_, (T*)buffer_->data(),
183  buffer_->size() / sizeof(T));
184  } else {
185  core::print_memory_slice(data_, size_, NULL, 0);
186  }
187  }
188 
189  //! Access to an element of the Slice with an array style.
190  T& operator[](const size_t i) const {
191  if (data_ == NULL) {
192  roc_panic("slice: null slice");
193  }
194  if (i > size_) {
195  roc_panic("slice: out of bounds: available=[%lu,%lu) requested=%lu",
196  (unsigned long)0, (unsigned long)size_, (unsigned long)i);
197  }
198  return data_[i];
199  }
200 
201  //! Convert to bool.
202  //! @returns
203  //! true if the slice is attached to buffer, even if it has zero length.
204  operator const struct unspecified_bool *() const {
205  return (const unspecified_bool*)data_;
206  }
207 
208 private:
209  BufferPtr buffer_;
210  T* data_;
211  size_t size_;
212 };
213 
214 } // namespace core
215 } // namespace roc
216 
217 #endif // ROC_CORE_SLICE_H_
Buffer.
Fixed-size dynamically-allocated byte buffer.
Definition: buffer.h:40
size_t size() const
Get buffer size in bytes.
Definition: buffer.h:46
uint8_t * data()
Get buffer data.
Definition: buffer.h:51
Slice.
Definition: slice.h:55
Slice subslice(size_t from, size_t to) const
Construct a slice pointing to a part of this slice.
Definition: slice.h:162
T * data_end() const
Pointer to the next after the last element in slice.
Definition: slice.h:101
size_t capacity() const
Get maximum possible number of elements in slice.
Definition: slice.h:114
Slice(Buffer &buffer, size_t from, size_t to)
Construct slice pointing to a part of a buffer.
Definition: slice.h:77
T * data() const
Get slice data.
Definition: slice.h:93
T * extend(const size_t add_sz)
Increase size() by add_sz.
Definition: slice.h:146
T & operator[](const size_t i) const
Access to an element of the Slice with an array style.
Definition: slice.h:190
void reslice(size_t from, size_t to)
Change slice beginning and ending inside the buffer.
Definition: slice.h:126
void print() const
Print slice to stderr.
Definition: slice.h:180
Slice(const BufferPtr &buffer)
Construct slice pointing to the whole buffer.
Definition: slice.h:65
Slice()
Construct empty slice.
Definition: slice.h:58
size_t size() const
Get number of elements in slice.
Definition: slice.h:109
void print_memory_slice(const uint8_t *inner, size_t inner_size, const uint8_t *outer, size_t outer_size)
Print memory slice.
Root namespace.
#define roc_panic(...)
Print error message and terminate program gracefully.
Definition: panic.h:50
Print memory to console.
Shared ownership intrusive pointer.