1 /*
2   ==============================================================================
3 
4    This file is part of the Water library.
5    Copyright (c) 2016 ROLI Ltd.
6    Copyright (C) 2017 Filipe Coelho <falktx@falktx.com>
7 
8    Permission is granted to use this software under the terms of the ISC license
9    http://www.isc.org/downloads/software-support-policy/isc-license/
10 
11    Permission to use, copy, modify, and/or distribute this software for any
12    purpose with or without fee is hereby granted, provided that the above
13    copyright notice and this permission notice appear in all copies.
14 
15    THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16    TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18    OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19    USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20    TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21    OF THIS SOFTWARE.
22 
23   ==============================================================================
24 */
25 
26 #ifndef WATER_MEMORYBLOCK_H_INCLUDED
27 #define WATER_MEMORYBLOCK_H_INCLUDED
28 
29 #include "HeapBlock.h"
30 
31 namespace water {
32 
33 //==============================================================================
34 /**
35     A class to hold a resizable block of raw data.
36 
37 */
38 class MemoryBlock
39 {
40 public:
41     //==============================================================================
42     /** Create an uninitialised block with 0 size. */
43     MemoryBlock() noexcept;
44 
45     /** Creates a memory block with a given initial size.
46 
47         @param initialSize          the size of block to create
48         @param initialiseToZero     whether to clear the memory or just leave it uninitialised
49     */
50     MemoryBlock (const size_t initialSize,
51                  bool initialiseToZero = false);
52 
53     /** Creates a copy of another memory block. */
54     MemoryBlock (const MemoryBlock&);
55 
56     /** Creates a memory block using a copy of a block of data.
57 
58         @param dataToInitialiseFrom     some data to copy into this block
59         @param sizeInBytes              how much space to use
60     */
61     MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
62 
63     /** Destructor. */
64     ~MemoryBlock() noexcept;
65 
66     /** Copies another memory block onto this one.
67         This block will be resized and copied to exactly match the other one.
68     */
69     MemoryBlock& operator= (const MemoryBlock&);
70 
71    #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
72     MemoryBlock (MemoryBlock&&) noexcept;
73     MemoryBlock& operator= (MemoryBlock&&) noexcept;
74    #endif
75 
76     //==============================================================================
77     /** Compares two memory blocks.
78         @returns true only if the two blocks are the same size and have identical contents.
79     */
80     bool operator== (const MemoryBlock& other) const noexcept;
81 
82     /** Compares two memory blocks.
83         @returns true if the two blocks are different sizes or have different contents.
84     */
85     bool operator!= (const MemoryBlock& other) const noexcept;
86 
87     /** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. */
88     bool matches (const void* data, size_t dataSize) const noexcept;
89 
90     //==============================================================================
91     /** Returns a void pointer to the data.
92 
93         Note that the pointer returned will probably become invalid when the
94         block is resized.
95     */
getData()96     void* getData() const noexcept                                  { return data; }
97 
98     /** Returns a byte from the memory block.
99         This returns a reference, so you can also use it to set a byte.
100     */
101     template <typename Type>
102     char& operator[] (const Type offset) const noexcept             { return data [offset]; }
103 
104 
105     //==============================================================================
106     /** Returns the block's current allocated size, in bytes. */
getSize()107     size_t getSize() const noexcept                                 { return size; }
108 
109     /** Resizes the memory block.
110 
111         Any data that is present in both the old and new sizes will be retained.
112         When enlarging the block, the new space that is allocated at the end can either be
113         cleared, or left uninitialised.
114 
115         @param newSize                      the new desired size for the block
116         @param initialiseNewSpaceToZero     if the block gets enlarged, this determines
117                                             whether to clear the new section or just leave it
118                                             uninitialised
119         @see ensureSize
120     */
121     void setSize (const size_t newSize,
122                   bool initialiseNewSpaceToZero = false);
123 
124     /** Increases the block's size only if it's smaller than a given size.
125 
126         @param minimumSize                  if the block is already bigger than this size, no action
127                                             will be taken; otherwise it will be increased to this size
128         @param initialiseNewSpaceToZero     if the block gets enlarged, this determines
129                                             whether to clear the new section or just leave it
130                                             uninitialised
131         @see setSize
132     */
133     void ensureSize (const size_t minimumSize,
134                      bool initialiseNewSpaceToZero = false);
135 
136     /** Frees all the blocks data, setting its size to 0. */
137     void reset();
138 
139     //==============================================================================
140     /** Fills the entire memory block with a repeated byte value.
141         This is handy for clearing a block of memory to zero.
142     */
143     void fillWith (uint8 valueToUse) noexcept;
144 
145     /** Adds another block of data to the end of this one.
146         The data pointer must not be null. This block's size will be increased accordingly.
147     */
148     void append (const void* data, size_t numBytes);
149 
150     /** Resizes this block to the given size and fills its contents from the supplied buffer.
151         The data pointer must not be null.
152     */
153     void replaceWith (const void* data, size_t numBytes);
154 
155     /** Inserts some data into the block.
156         The dataToInsert pointer must not be null. This block's size will be increased accordingly.
157         If the insert position lies outside the valid range of the block, it will be clipped to
158         within the range before being used.
159     */
160     void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
161 
162     /** Chops out a section  of the block.
163 
164         This will remove a section of the memory block and close the gap around it,
165         shifting any subsequent data downwards and reducing the size of the block.
166 
167         If the range specified goes beyond the size of the block, it will be clipped.
168     */
169     void removeSection (size_t startByte, size_t numBytesToRemove);
170 
171     //==============================================================================
172     /** Copies data into this MemoryBlock from a memory address.
173 
174         @param srcData              the memory location of the data to copy into this block
175         @param destinationOffset    the offset in this block at which the data being copied should begin
176         @param numBytes             how much to copy in (if this goes beyond the size of the memory block,
177                                     it will be clipped so not to do anything nasty)
178     */
179     void copyFrom (const void* srcData,
180                    int destinationOffset,
181                    size_t numBytes) noexcept;
182 
183     /** Copies data from this MemoryBlock to a memory address.
184 
185         @param destData         the memory location to write to
186         @param sourceOffset     the offset within this block from which the copied data will be read
187         @param numBytes         how much to copy (if this extends beyond the limits of the memory block,
188                                 zeros will be used for that portion of the data)
189     */
190     void copyTo (void* destData,
191                  int sourceOffset,
192                  size_t numBytes) const noexcept;
193 
194     //==============================================================================
195     /** Exchanges the contents of this and another memory block.
196         No actual copying is required for this, so it's very fast.
197     */
198     void swapWith (MemoryBlock& other) noexcept;
199 
200     //==============================================================================
201     /** Release this object's data ownership, returning the data pointer. */
202     void* release () noexcept;
203 
204     //==============================================================================
205     /** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
206     String toString() const;
207 
208     //==============================================================================
209     /** Parses a string of hexadecimal numbers and writes this data into the memory block.
210 
211         The block will be resized to the number of valid bytes read from the string.
212         Non-hex characters in the string will be ignored.
213 
214         @see String::toHexString()
215     */
216     void loadFromHexString (StringRef sourceHexString);
217 
218     //==============================================================================
219     /** Sets a number of bits in the memory block, treating it as a long binary sequence. */
220     void setBitRange (size_t bitRangeStart,
221                       size_t numBits,
222                       int binaryNumberToApply) noexcept;
223 
224     /** Reads a number of bits from the memory block, treating it as one long binary sequence */
225     int getBitRange (size_t bitRangeStart,
226                      size_t numBitsToRead) const noexcept;
227 
228 private:
229     //==============================================================================
230     HeapBlock<char> data;
231     size_t size;
232 };
233 
234 }
235 
236 #endif // WATER_MEMORYBLOCK_H_INCLUDED
237