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