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"
17#include "roc_core/shared_ptr.h"
18
19namespace roc {
20namespace 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.
54template <class T> class Slice {
55public:
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
206private:
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 * extend(const size_t add_sz)
Increase size() by add_sz.
Definition: slice.h:145
size_t capacity() const
Get maximum possible number of elements in slice.
Definition: slice.h:113
Slice(const SharedPtr< Buffer< T > > &buffer)
Construct slice pointing to the whole buffer.
Definition: slice.h:64
T * data_end() const
Pointer to the next after the last element in slice.
Definition: slice.h:100
T & operator[](const size_t i) const
Access to an element of the Slice with an array style.
Definition: slice.h:188
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
T * data() const
Get slice data.
Definition: slice.h:92
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.