athena/include/athena/MemoryWriter.hpp
Lioncash 016e14c460 MemoryWriter: Initialize member variables to deterministic values
Makes the variable initialization behavior deterministic in the case of
the default constructor. This also eliminates the possibility of an
uninitialized read from occurring within the destructor entirely; even
in the face of future changes.
2019-09-05 01:12:07 -04:00

150 lines
5.2 KiB
C++

#pragma once
#include <memory>
#include <string>
#include "athena/IStreamWriter.hpp"
namespace athena::io {
/*! @class MemoryWriter
* @brief A Stream class for writing data to a memory position
*
* A Class for writing binary data to a file or memory stream,
* all work is done using a memory buffer, and not written directly to the disk
* this allows for fast, flexible code as well as the ability to quickly modify data
* @sa Stream
*/
class MemoryWriter : public IStreamWriter {
public:
~MemoryWriter() override;
/*! @brief This constructor references an existing buffer to write to in-place.
*
* @param data The existing buffer.
* @param length The length of the existing buffer.
* @param takeOwnership Whether or not this writer takes ownership of the supplied data buffer.
* If true, the buffer will be deleted by this when the destructor executes.
*/
explicit MemoryWriter(atUint8* data, atUint64 length, bool takeOwnership = false);
/*! @brief Sets the buffers position relative to the specified position.<br />
* It seeks relative to the current position by default.
* @param position where in the buffer to seek
* @param origin The Origin to seek @sa SeekOrigin
*/
void seek(atInt64 position, SeekOrigin origin = SeekOrigin::Current) override;
/*! @brief Returns the current position in the stream.
*
* @return Int64 The current position in the stream.
*/
atUint64 position() const override { return m_position; }
/*! @brief Returns the length of the stream.
*
* @return Int64 The length of the stream.
*/
atUint64 length() const override { return m_length; }
bool isOpen() const { return true; }
/** @brief Sets the buffer to the given one, deleting the current one if it owns it.<br />
* @param data The new buffer.
* @param length The length of the new buffer.
* @param takeOwnership Whether the Stream now owns the buffer.
*/
void setData(atUint8* data, atUint64 length, bool takeOwnership = false);
/*! @brief Returns a copy of the current buffer.<br />
* Changes to the copy do not affect the buffer so it's perfectly safe to
* directly edit the buffer and use setData to set the new information.<br />
* @return Uint8* The copy of the buffer.
*/
atUint8* data() const;
/*! @brief Sets the target file
*
* @param filepath The path to write to.
*/
void setFilepath(const std::string& filepath) { m_filepath = filepath; }
/*! @brief
* Returns the target file
*/
std::string filepath() const { return m_filepath; }
/*! @brief Saves the file to the specified file.
*
* @param filename If not empty, the filename to save to
*/
void save(std::string_view filename = {});
/*! @brief Writes the given buffer with the specified length, buffers can be bigger than the length
* however it's undefined behavior to try and write a buffer which is smaller than the given length.
* If you are needing to fill in an area please use IStreamWriter::fill(atUint64) instead.
*
* @param data The buffer to write
* @param length The amount to write
*/
void writeUBytes(const atUint8* data, atUint64 length) override;
protected:
MemoryWriter() = default;
atUint8* m_data = nullptr;
atUint64 m_length = 0;
atUint64 m_position = 0;
bool m_bufferOwned = false;
std::string m_filepath; //!< Path to the target file
};
class MemoryCopyWriter : public MemoryWriter {
public:
/*! @brief This constructor copies an existing buffer to write to.
*
* @param data The existing buffer
* @param length The length of the existing buffer
*/
explicit MemoryCopyWriter(atUint8* data = nullptr, atUint64 length = 0x10);
/*! @brief This constructor creates an instance from a file on disk.
*
* @param filename The file to create the stream from
*/
explicit MemoryCopyWriter(std::string_view filename);
/*! @brief Sets the buffers position relative to the specified position.<br />
* It seeks relative to the current position by default.
* @param position where in the buffer to seek
* @param origin The Origin to seek @sa SeekOrigin
*/
void seek(atInt64 position, SeekOrigin origin = SeekOrigin::Current) override;
/*! @brief Sets the buffer to the given one, deleting the current one.<br />
* <b>BEWARE:</b> As this deletes the current buffer it WILL cause a loss of data
* if that was not the intent.<br />
* Once you pass the data to setData <b>DO NOT</b> delete the buffer
* as Stream now owns the address, this is done to keep memory usage down.
* @param data The new buffer.
* @param length The length of the new buffer.
* @throw IOException
*/
void setData(const atUint8* data, atUint64 length);
/*! @brief Writes the given buffer with the specified length, buffers can be bigger than the length
* however it's undefined behavior to try and write a buffer which is smaller than the given length.
*
* @param data The buffer to write
* @param length The amount to write
*/
void writeUBytes(const atUint8* data, atUint64 length) override;
protected:
std::unique_ptr<atUint8[]> m_dataCopy;
private:
void resize(atUint64 newSize);
};
} // namespace athena::io