File: MemoryStream.h

package info (click to toggle)
audacity 3.7.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 134,800 kB
  • sloc: cpp: 366,277; ansic: 198,323; lisp: 7,761; sh: 3,414; python: 1,501; xml: 1,385; perl: 854; makefile: 125
file content (103 lines) | stat: -rw-r--r-- 2,635 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**********************************************************************

  Audacity: A Digital Audio Editor

  MemoryStream.h

  Dmitry Vedenko

**********************************************************************/

#pragma once

#include <array>
#include <cstdint>
#include <list>
#include <vector>

#include "IteratorX.h"

/*!
 * @brief A low overhead memory stream with O(1) append, low heap fragmentation and a linear memory view.
 *
 * wxMemoryBuffer always appends 1Kb to the end of the buffer, causing severe performance issues
 * and significant heap fragmentation. There is no possibility to control the increment value.
 *
 * std::vector doubles its memory size which can be problematic for large projects as well.
 * Not as bad as wxMemoryBuffer though.
 * 
 */
class UTILITY_API MemoryStream final
{
public:
   using StreamData = std::vector<uint8_t>;
   using StreamChunk = std::pair<const void*, size_t>;

private:
   static constexpr size_t ChunkSize =
      1024 * 1024 - // 1Mb
      2 * sizeof(void*) - // account for the list node pointers
      sizeof(size_t); // account for the bytes used member

   struct Chunk final
   {
      std::array<uint8_t, ChunkSize> Data;
      size_t BytesUsed { 0 };

      // Returns data size left to append
      size_t Append(StreamChunk& dataView);
   };

   using ChunksList = std::list<Chunk>;

public:

   MemoryStream() = default;
   MemoryStream(MemoryStream&&) = default;

   void Clear();

   void AppendByte(char data);
   void AppendData(const void* data, const size_t length);

   // This function possibly has O(size) complexity as it may
   // require copying bytes to a linear chunk
   const void* GetData() const;
   const size_t GetSize() const noexcept;

   bool IsEmpty() const noexcept;

   struct UTILITY_API Iterator :
       ValueIterator<const StreamChunk, std::forward_iterator_tag>
   {
      Iterator(const Iterator&) = default;

      Iterator& operator++();

      Iterator operator++(int);

      StreamChunk operator*() const;
      StreamChunk operator->() const;

      bool operator==(const Iterator& rhs) const noexcept;
      bool operator!=(const Iterator& rhs) const noexcept;
   private:
      Iterator(const MemoryStream* stream, bool isBegin);
      
      const MemoryStream* mStream { nullptr };
      ChunksList::const_iterator mListIterator;
      bool mShowLinearPart { false };

      friend class MemoryStream;
   };

   Iterator begin() const;
   Iterator end() const;

private:
   // This structures are lazily updated by get data
   mutable ChunksList mChunks;
   mutable StreamData mLinearData;

   size_t mDataSize { 0 };
};