JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_BufferedInputStream.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26static int calcBufferStreamBufferSize (int requestedSize, InputStream* source) noexcept
27{
28 // You need to supply a real stream when creating a BufferedInputStream
29 jassert (source != nullptr);
30
32 auto sourceSize = source->getTotalLength();
33
35 return jmax (32, (int) sourceSize);
36
37 return requestedSize;
38}
39
40//==============================================================================
42 : source (sourceStream, takeOwnership),
43 bufferedRange (sourceStream->getPosition(), sourceStream->getPosition()),
44 position (bufferedRange.getStart()),
45 bufferLength (calcBufferStreamBufferSize (size, sourceStream))
46{
47 buffer.malloc (bufferLength);
48}
49
51 : BufferedInputStream (&sourceStream, size, false)
52{
53}
54
56
57//==============================================================================
59{
60 if (! ensureBuffered())
61 return 0;
62
63 return position < lastReadPos ? buffer[(int) (position - bufferedRange.getStart())] : 0;
64}
65
67{
68 return source->getTotalLength();
69}
70
72{
73 return position;
74}
75
77{
78 position = jmax ((int64) 0, newPosition);
79 return true;
80}
81
83{
84 return position >= lastReadPos && source->isExhausted();
85}
86
87bool BufferedInputStream::ensureBuffered()
88{
89 auto bufferEndOverlap = lastReadPos - bufferOverlap;
90
91 if (position < bufferedRange.getStart() || position >= bufferEndOverlap)
92 {
93 int bytesRead = 0;
94
95 if (position < lastReadPos
96 && position >= bufferEndOverlap
97 && position >= bufferedRange.getStart())
98 {
99 auto bytesToKeep = (int) (lastReadPos - position);
100 memmove (buffer, buffer + (int) (position - bufferedRange.getStart()), (size_t) bytesToKeep);
101
102 bytesRead = source->read (buffer + bytesToKeep,
103 (int) (bufferLength - bytesToKeep));
104
105 if (bytesRead < 0)
106 return false;
107
108 lastReadPos += bytesRead;
109 bytesRead += bytesToKeep;
110 }
111 else
112 {
113 if (! source->setPosition (position))
114 return false;
115
116 bytesRead = (int) source->read (buffer, (size_t) bufferLength);
117
118 if (bytesRead < 0)
119 return false;
120
121 lastReadPos = position + bytesRead;
122 }
123
124 bufferedRange = Range<int64> (position, lastReadPos);
125
126 while (bytesRead < bufferLength)
127 buffer[bytesRead++] = 0;
128 }
129
130 return true;
131}
132
134{
135 const auto initialPosition = position;
136
137 const auto getBufferedRange = [this] { return bufferedRange; };
138
140 {
141 memcpy (static_cast<char*> (destBuffer) + (rangeToRead.getStart() - initialPosition),
142 buffer + (rangeToRead.getStart() - bufferedRange.getStart()),
143 (size_t) rangeToRead.getLength());
144 };
145
146 const auto fillReservoir = [this] (int64 requestedStart)
147 {
148 position = requestedStart;
149 ensureBuffered();
150 };
151
152 const auto remaining = Reservoir::doBufferedRead (Range<int64> (position, position + maxBytesToRead),
156
157 const auto bytesRead = maxBytesToRead - remaining.getLength();
158 position = remaining.getStart();
159 return (int) bytesRead;
160}
161
163{
164 if (position >= bufferedRange.getStart()
165 && position < lastReadPos)
166 {
167 auto maxChars = (int) (lastReadPos - position);
168 auto* src = buffer + (int) (position - bufferedRange.getStart());
169
170 for (int i = 0; i < maxChars; ++i)
171 {
172 if (src[i] == 0)
173 {
174 position += i + 1;
175 return String::fromUTF8 (src, i);
176 }
177 }
178 }
179
181}
182
183
184//==============================================================================
185//==============================================================================
186#if JUCE_UNIT_TESTS
187
189{
190 template <typename Fn, size_t... Ix, typename Values>
191 static void applyImpl (Fn&& fn, std::index_sequence<Ix...>, Values&& values)
192 {
193 fn (std::get<Ix> (values)...);
194 }
195
196 template <typename Fn, typename... Values>
197 static void apply (Fn&& fn, std::tuple<Values...> values)
198 {
199 applyImpl (fn, std::make_index_sequence<sizeof... (Values)>(), values);
200 }
201
202 template <typename Fn, typename Values>
203 static void allCombinationsImpl (Fn&& fn, Values&& values)
204 {
205 apply (fn, values);
206 }
207
208 template <typename Fn, typename Values, typename Range, typename... Ranges>
209 static void allCombinationsImpl (Fn&& fn, Values&& values, Range&& range, Ranges&&... ranges)
210 {
211 for (auto& item : range)
212 allCombinationsImpl (fn, std::tuple_cat (values, std::tie (item)), ranges...);
213 }
214
215 template <typename Fn, typename... Ranges>
216 static void allCombinations (Fn&& fn, Ranges&&... ranges)
217 {
218 allCombinationsImpl (fn, std::tie(), ranges...);
219 }
220
222 : UnitTest ("BufferedInputStream", UnitTestCategories::streams)
223 {}
224
225 void runTest() override
226 {
227 const MemoryBlock testBufferA ("abcdefghijklmnopqrstuvwxyz", 26);
228
229 const auto testBufferB = [&]
230 {
231 MemoryBlock mb { 8192 };
232 auto r = getRandom();
233
234 std::for_each (mb.begin(), mb.end(), [&] (char& item)
235 {
236 item = (char) r.nextInt (std::numeric_limits<char>::max());
237 });
238
239 return mb;
240 }();
241
242 const MemoryBlock buffers[] { testBufferA, testBufferB };
243 const int readSizes[] { 3, 10, 50 };
244 const bool shouldPeek[] { false, true };
245
246 const auto runTest = [this] (const MemoryBlock& data, const int readSize, const bool peek)
247 {
248 MemoryInputStream mi (data, true);
249
250 BufferedInputStream stream (mi, jmin (200, (int) data.getSize()));
251
252 beginTest ("Read");
253
254 expectEquals (stream.getPosition(), (int64) 0);
255 expectEquals (stream.getTotalLength(), (int64) data.getSize());
256 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
257 expect (! stream.isExhausted());
258
259 size_t numBytesRead = 0;
260 MemoryBlock readBuffer (data.getSize());
261
262 while (numBytesRead < data.getSize())
263 {
264 if (peek)
265 expectEquals (stream.peekByte(), *(char*) (data.begin() + numBytesRead));
266
267 const auto startingPos = numBytesRead;
268 numBytesRead += (size_t) stream.read (readBuffer.begin() + numBytesRead, readSize);
269
270 expect (std::equal (readBuffer.begin() + startingPos,
271 readBuffer.begin() + numBytesRead,
272 data.begin() + startingPos,
273 data.begin() + numBytesRead));
274 expectEquals (stream.getPosition(), (int64) numBytesRead);
275 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
276 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
277 }
278
279 expectEquals (stream.getPosition(), (int64) data.getSize());
280 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
281 expect (stream.isExhausted());
282
283 expect (readBuffer == data);
284
285 beginTest ("Skip");
286
287 stream.setPosition (0);
288 expectEquals (stream.getPosition(), (int64) 0);
289 expectEquals (stream.getTotalLength(), (int64) data.getSize());
290 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
291 expect (! stream.isExhausted());
292
293 numBytesRead = 0;
294 const int numBytesToSkip = 5;
295
296 while (numBytesRead < data.getSize())
297 {
298 expectEquals (stream.peekByte(), *(char*) (data.begin() + numBytesRead));
299
300 stream.skipNextBytes (numBytesToSkip);
302 numBytesRead = std::min (numBytesRead, data.getSize());
303
304 expectEquals (stream.getPosition(), (int64) numBytesRead);
305 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
306 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
307 }
308
309 expectEquals (stream.getPosition(), (int64) data.getSize());
310 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
311 expect (stream.isExhausted());
312 };
313
315 }
316};
317
319
320#endif
321
322} // namespace juce
T apply(T... args)
Wraps another input stream, and reads from it using an intermediate buffer.
~BufferedInputStream() override
Destructor.
BufferedInputStream(InputStream *sourceStream, int bufferSize, bool deleteSourceWhenDestroyed)
Creates a BufferedInputStream from an input source.
int64 getPosition() override
Returns the offset of the next byte that will be read from the stream.
char peekByte()
Returns the next byte that would be read by a call to readByte()
bool isExhausted() override
Returns true if the stream has no more data to read.
String readString() override
Reads a zero-terminated UTF-8 string from the stream.
int read(void *destBuffer, int maxBytesToRead) override
Reads some data from the stream into a memory buffer.
int64 getTotalLength() override
Returns the total number of bytes available for reading in this stream.
bool setPosition(int64 newPosition) override
Tries to move the current read position of the stream.
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
Allocates a specified amount of memory.
The base class for streams that read data.
virtual String readString()
Reads a zero-terminated UTF-8 string from the stream.
A general-purpose range object, that simply represents any linear range with a start and end point.
Definition juce_Range.h:40
constexpr ValueType getStart() const noexcept
Returns the start of the range.
Definition juce_Range.h:80
The JUCE String class!
Definition juce_String.h:53
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
This is a base class for classes that perform a unit test.
T data(T... args)
T equal(T... args)
T for_each(T... args)
#define jassert(expression)
Platform-independent assertion macro.
typedef int
memcpy
memmove
T min(T... args)
JUCE Namespace.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
constexpr Type jmax(Type a, Type b)
Returns the larger of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
long long int64
A platform-independent 64-bit integer type.
static Range< Index > doBufferedRead(Range< Index > rangeToRead, GetBufferedRange &&getBufferedRange, ReadFromReservoir &&readFromReservoir, FillReservoir &&fillReservoir)
Attempts to read the requested range from some kind of input stream, with intermediate buffering in a...
typedef size_t
T tie(T... args)
T tuple_cat(T... args)