Audacity 3.2.0
libraries/lib-utility/memorystream.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 MemoryStream.cpp
6
7 Dmitry Vedenko
8
9**********************************************************************/
10
11#include "MemoryStream.h"
12
13#include <algorithm>
14
16{
17 mChunks = {};
18 mLinearData = {};
19 mDataSize = 0;
20}
21
23{
24 AppendData(&data, 1);
25}
26
27void MemoryStream::AppendData(const void* data, const size_t length)
28{
29 if (mChunks.empty())
30 mChunks.emplace_back();
31
32 StreamChunk dataView = { data, length };
33
34 while (mChunks.back().Append(dataView) > 0)
35 mChunks.emplace_back();
36
37 mDataSize += length;
38}
39
40const void* MemoryStream::GetData() const
41{
42 if (!mChunks.empty())
43 {
44 const size_t desiredSize = GetSize();
45
46 mLinearData.reserve(desiredSize);
47
48 for (const Chunk& chunk : mChunks)
49 {
50 auto begin = chunk.Data.begin();
51 auto end = begin + chunk.BytesUsed;
52
53 mLinearData.insert(mLinearData.end(), begin, end);
54 }
55
56 mChunks = {};
57 }
58
59 return mLinearData.data();
60}
61
62const size_t MemoryStream::GetSize() const noexcept
63{
64 return mDataSize;
65}
66
68{
69 const size_t dataSize = dataView.second;
70
71 const size_t bytesToWrite = std::min(ChunkSize - BytesUsed, dataSize);
72 const size_t bytesLeft = dataSize - bytesToWrite;
73
74 const uint8_t* beginData = static_cast<const uint8_t*>(dataView.first);
75 const uint8_t* endData = beginData + bytesToWrite;
76
77 // Some extreme micro optimization for MSVC (at least)
78 // std::copy will generate a call to memmove in any case
79 // which will be slower than just writing the byte
80 if (bytesToWrite == 1)
81 {
82 Data[BytesUsed] = *beginData;
83 }
84 else
85 {
86 // There is a chance for unaligned access, so we do no handle
87 // types as int32_t separately. Unaligned access is slow on x86
88 // and fails horribly on ARM
89 std::copy(beginData, endData, Data.begin() + BytesUsed);
90 }
91
92 dataView.first = endData;
93 dataView.second = bytesLeft;
94
95 BytesUsed += bytesToWrite;
96
97 return bytesLeft;
98}
99
100bool MemoryStream::IsEmpty() const noexcept
101{
102 return mDataSize == 0;
103}
104
106{
107 return Iterator(this, true);
108}
109
111{
112 return Iterator(this, false);
113}
114
116 : mStream(stream)
117 , mListIterator(isBegin ? mStream->mChunks.cbegin() : mStream->mChunks.cend())
118 , mShowLinearPart(isBegin && mStream->mLinearData.size() > 0)
119{
120}
121
123{
124 if (mShowLinearPart)
125 mShowLinearPart = false;
126 else
127 ++mListIterator;
128
129 return *this;
130}
131
133{
134 Iterator result { *this };
135 this->operator++();
136 return result;
137}
138
140{
141 if (mShowLinearPart)
142 return { mStream->mLinearData.data(), mStream->mLinearData.size() };
143
144 return { mListIterator->Data.data(), mListIterator->BytesUsed };
145}
146
148{
149 return this->operator*();
150}
151
152bool MemoryStream::Iterator::operator!=(const Iterator& rhs) const noexcept
153{
154 return !(*this == rhs);
155}
156
157bool MemoryStream::Iterator::operator==(const Iterator& rhs) const noexcept
158{
159 return mStream == rhs.mStream && mListIterator == rhs.mListIterator &&
160 mShowLinearPart == rhs.mShowLinearPart;
161}
int min(int a, int b)
Vector operator*(const Vector &left, const Vector &right)
Definition: Matrix.cpp:153
A low overhead memory stream with O(1) append, low heap fragmentation and a linear memory view.
const size_t GetSize() const noexcept
std::pair< const void *, size_t > StreamChunk
void AppendData(const void *data, const size_t length)
static constexpr size_t ChunkSize
size_t Append(StreamChunk &dataView)
std::array< uint8_t, ChunkSize > Data
Iterator(const Iterator &)=default
bool operator==(const Iterator &rhs) const noexcept
bool operator!=(const Iterator &rhs) const noexcept