26static int calcBufferStreamBufferSize (
int requestedSize, InputStream* source)
noexcept
29 jassert (source !=
nullptr);
31 requestedSize = jmax (256, requestedSize);
32 auto sourceSize = source->getTotalLength();
34 if (sourceSize >= 0 && sourceSize < requestedSize)
35 return jmax (32, (
int) sourceSize);
43 bufferedRange (sourceStream->getPosition(), sourceStream->getPosition()),
44 position (bufferedRange.getStart()),
45 bufferLength (calcBufferStreamBufferSize (size, sourceStream))
47 buffer.
malloc (bufferLength);
60 if (! ensureBuffered())
63 return position < lastReadPos ? buffer[(
int) (position - bufferedRange.
getStart())] : 0;
68 return source->getTotalLength();
84 return position >= lastReadPos && source->isExhausted();
87bool BufferedInputStream::ensureBuffered()
95 if (position < lastReadPos
97 && position >= bufferedRange.
getStart())
108 lastReadPos += bytesRead;
113 if (! source->setPosition (position))
116 bytesRead = (int) source->read (buffer, (
size_t) bufferLength);
121 lastReadPos = position + bytesRead;
124 bufferedRange = Range<int64> (position, lastReadPos);
126 while (bytesRead < bufferLength)
127 buffer[bytesRead++] = 0;
159 return (
int) bytesRead;
164 if (position >= bufferedRange.
getStart()
165 && position < lastReadPos)
190 template <
typename Fn,
size_t...
Ix,
typename Values>
191 static void applyImpl (Fn&& fn, std::index_sequence<Ix...>,
Values&& values)
193 fn (std::get<Ix> (values)...);
196 template <
typename Fn,
typename... Values>
197 static void apply (Fn&& fn, std::tuple<Values...> values)
199 applyImpl (fn, std::make_index_sequence<
sizeof... (Values)>(), values);
202 template <
typename Fn,
typename Values>
203 static void allCombinationsImpl (Fn&& fn, Values&& values)
208 template <
typename Fn,
typename Values,
typename Range,
typename... Ranges>
209 static void allCombinationsImpl (Fn&& fn, Values&& values, Range&& range, Ranges&&... ranges)
211 for (
auto& item : range)
212 allCombinationsImpl (fn, std::tuple_cat (values, std::tie (item)), ranges...);
215 template <
typename Fn,
typename... Ranges>
216 static void allCombinations (Fn&& fn, Ranges&&... ranges)
218 allCombinationsImpl (fn, std::tie(), ranges...);
221 BufferedInputStreamTests()
222 : UnitTest (
"BufferedInputStream", UnitTestCategories::streams)
225 void runTest()
override
227 const MemoryBlock testBufferA (
"abcdefghijklmnopqrstuvwxyz", 26);
229 const auto testBufferB = [&]
231 MemoryBlock mb { 8192 };
232 auto r = getRandom();
234 std::for_each (mb.begin(), mb.end(), [&] (
char& item)
236 item = (char) r.nextInt (std::numeric_limits<char>::max());
242 const MemoryBlock buffers[] { testBufferA, testBufferB };
243 const int readSizes[] { 3, 10, 50 };
244 const bool shouldPeek[] {
false,
true };
246 const auto runTest = [
this] (
const MemoryBlock& data,
const int readSize,
const bool peek)
248 MemoryInputStream mi (data,
true);
250 BufferedInputStream stream (mi, jmin (200, (
int) data.getSize()));
254 expectEquals (stream.getPosition(), (int64) 0);
255 expectEquals (stream.getTotalLength(), (int64) data.getSize());
256 expectEquals (stream.getNumBytesRemaining(), stream.getTotalLength());
257 expect (! stream.isExhausted());
259 size_t numBytesRead = 0;
260 MemoryBlock readBuffer (data.getSize());
262 while (numBytesRead < data.getSize())
265 expectEquals (stream.peekByte(), *(
char*) (data.begin() + numBytesRead));
267 const auto startingPos = numBytesRead;
268 numBytesRead += (size_t) stream.read (readBuffer.begin() + numBytesRead, readSize);
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()));
279 expectEquals (stream.getPosition(), (int64) data.getSize());
280 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
281 expect (stream.isExhausted());
283 expect (readBuffer == data);
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());
294 const int numBytesToSkip = 5;
296 while (numBytesRead < data.getSize())
298 expectEquals (stream.peekByte(), *(
char*) (data.begin() + numBytesRead));
300 stream.skipNextBytes (numBytesToSkip);
301 numBytesRead += numBytesToSkip;
302 numBytesRead = std::min (numBytesRead, data.getSize());
304 expectEquals (stream.getPosition(), (int64) numBytesRead);
305 expectEquals (stream.getNumBytesRemaining(), (int64) (data.getSize() - numBytesRead));
306 expect (stream.isExhausted() == (numBytesRead == data.getSize()));
309 expectEquals (stream.getPosition(), (int64) data.getSize());
310 expectEquals (stream.getNumBytesRemaining(), (int64) 0);
311 expect (stream.isExhausted());
314 allCombinations (runTest, buffers, readSizes, shouldPeek);
318static BufferedInputStreamTests bufferedInputStreamTests;
void malloc(SizeType newNumElements, size_t elementSize=sizeof(ElementType))
constexpr ValueType getStart() const noexcept
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
static Range< Index > doBufferedRead(Range< Index > rangeToRead, GetBufferedRange &&getBufferedRange, ReadFromReservoir &&readFromReservoir, FillReservoir &&fillReservoir)