If I understand it correctly, you don't need manual memory management at all and you don't need to preserve the original memory blocks positions in memory. In that case, you could use std::vector
to store the blocks - and squash them into one big block if you wish.
Example:
#include <cstddef>
#include <cstdint>
#include <fstream>
#include <iostream>
#include <vector>
// A class to keep a number of blocks
class BlockMaster {
public:
using block_t = std::vector<uint8_t>;
explicit BlockMaster(size_t init_size = 0) : blocks{init_size} {}
// Add a new block
void AddDataStream(const uint8_t* begin, const uint8_t* end) {
blocks.emplace_back(begin, end);
}
size_t size() const noexcept { return blocks.size(); }
// random access to the stored blocks
block_t& operator[](size_t block_number) noexcept {
return blocks[block_number];
}
const block_t& operator[](size_t block_number) const noexcept {
return blocks[block_number];
}
// support for iterating over the stored blocks
auto cbegin() const noexcept { return blocks.cbegin(); }
auto cend() const noexcept { return blocks.cend(); }
auto begin() const noexcept { return cbegin(); }
auto end() const noexcept { return cend(); }
auto begin() noexcept { return blocks.begin(); }
auto end() noexcept { return blocks.end(); }
// create a BlockMaster with one huge block from the stored blocks
BlockMaster GetSquashedBlocks() {
BlockMaster result(1);
for(const block_t& block : *this) {
result[0].insert(result[0].end(), block.begin(), block.end());
}
return result;
}
private:
std::vector<block_t> blocks;
};
// stream all the stored blocks to a file (as if they were one big block, so
// you don't need to squash them for this)
std::ofstream& operator<<(std::ofstream& ofs, const BlockMaster& bm) {
for(const auto& block : bm)
ofs.write(reinterpret_cast<const char*>(block.data()),
static_cast<std::streamsize>(block.size()));
return ofs;
}
int main() {
unsigned char memory[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
BlockMaster bm;
bm.AddDataStream(memory + 0, memory + 3);
bm.AddDataStream(memory + 4, memory + 8);
std::cout << bm.size() << "\n--\n";
for(const auto& block : bm) {
std::cout << ' ' << block.size() << '\n';
}
bm = bm.GetSquashedBlocks();
std::cout << "--\n";
std::cout << bm.size() << "\n--\n";
for(const auto& block : bm) {
std::cout << ' ' << block.size() << '\n';
}
}
Output:
2 // blockmasters number of stored blocks
--
3 // first blocks size
4 // second blocks size
--
1 // blockmasters number of stored blocks after squashing
--
7 // size of the one block after squashing