Move most StreamBuffer code into base-buffer.hpp
This commit is contained in:
@@ -184,27 +184,17 @@
|
||||
//
|
||||
// You can use a streambuffer as a lua_Writer, as follows:
|
||||
//
|
||||
// lua_dump(L, stream.lua_writer(), stream.lua_writer_ud());
|
||||
// lua_dump(L, lua_writer_into_streambuffer, &sb);
|
||||
//
|
||||
// Anything written to the lua_writer gets appended to the streambuffer, the
|
||||
// same as if it had been written using write_bytes.
|
||||
//
|
||||
// You can use a streambuffer as a lua_Reader, as follows:
|
||||
// You can't use streambuffer as a lua_Reader directly, but you can get a
|
||||
// string_view out of it and then use that to construct a lua_Reader, as
|
||||
// follows:
|
||||
//
|
||||
// lua_load (L, stream.lua_reader(), stream.lua_reader_ud(nbytes), ...)
|
||||
//
|
||||
// The exact semantics of the lua_reader are tricky, so be careful:
|
||||
// lua_reader_ud calls 'read_bytes' immediately, and it stores the bytes in a
|
||||
// "cache of bytes for lua." Then, when the lua_reader gets invoked, the reader
|
||||
// returns the entire contents of the cache, and it clears the cache. Here are
|
||||
// some consequences of this design:
|
||||
//
|
||||
// 1. The number of bytes read from the stream is always exactly equal to
|
||||
// nbytes, even if lua never calls the lua_reader.
|
||||
//
|
||||
// 2. If the stream doesn't contain nbytes, a StreamEof exception gets thrown
|
||||
// from lua_reader_ud, not from the lua_Reader. This is good, because it
|
||||
// means exceptions don't get thrown from inside the lua runtime.
|
||||
// LuaStringViewReader svr(mystreambuffer.view());
|
||||
// lua_load (L, svr.lua_reader(), svr.lua_reader_userdata());
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -219,7 +209,7 @@
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "base-writer.hpp"
|
||||
#include "base-buffer.hpp"
|
||||
#include "luastack.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
@@ -229,188 +219,88 @@ public:
|
||||
virtual char const *what() const { return "General stream exception"; }
|
||||
};
|
||||
|
||||
class StreamEof : public StreamException
|
||||
class StreamEofOnRead : public StreamException
|
||||
{
|
||||
public:
|
||||
virtual char const *what() const { return "Stream ran out of data"; }
|
||||
};
|
||||
|
||||
class StreamCorruption : public StreamException
|
||||
class StreamStringTooLong: public StreamException
|
||||
{
|
||||
public:
|
||||
virtual char const *what() const { return "Stream contained invalid data"; }
|
||||
virtual char const *what() const { return "Stream contained a string that was too long"; }
|
||||
};
|
||||
|
||||
class StreamBuffer : public eng::nevernew, public BaseReader<StreamBuffer>, public BaseWriter<StreamBuffer> {
|
||||
class StreamIntegerTruncated: public StreamException
|
||||
{
|
||||
public:
|
||||
using read_string_type = eng::string;
|
||||
virtual char const *what() const { return "You truncated an integer when writing to a stream"; }
|
||||
};
|
||||
|
||||
// Construct an empty buffer.
|
||||
StreamBuffer();
|
||||
class StreamCorruption: public StreamException
|
||||
{
|
||||
public:
|
||||
virtual char const *what() const { return "Stream Corruption"; }
|
||||
};
|
||||
|
||||
// Construct an empty buffer, preallocate the specified amount of space.
|
||||
StreamBuffer(int64_t size, bool fixed_size);
|
||||
class StreamBufferCore {
|
||||
protected:
|
||||
void *basebuffer_malloc(size_t size) { return eng::malloc(size); }
|
||||
void basebuffer_free(void *p) { eng::free(p); }
|
||||
void clear_error_flags() { }
|
||||
void raise_eof_on_read() { throw StreamEofOnRead(); }
|
||||
void raise_string_too_long() { throw StreamStringTooLong(); }
|
||||
void raise_integer_truncated() { throw StreamIntegerTruncated(); }
|
||||
};
|
||||
|
||||
// Construct a streambuffer that reads from an external block of bytes.
|
||||
StreamBuffer(const char *s, int64_t len);
|
||||
class StreamBuffer : public eng::nevernew, public BaseBuffer<StreamBufferCore, eng::string> {
|
||||
public:
|
||||
using BaseBuffer::BaseBuffer;
|
||||
|
||||
// Construct a streambuffer that reads from an external block of bytes.
|
||||
StreamBuffer(std::string_view data);
|
||||
|
||||
// Delete a StreamBuffer.
|
||||
~StreamBuffer();
|
||||
|
||||
// Get the total number of bytes ever read from this buffer.
|
||||
int64_t total_reads() const;
|
||||
|
||||
// Get the total number of bytes ever written to this buffer.
|
||||
int64_t total_writes() const;
|
||||
|
||||
// Make the specified amount of space in the buffer for writing.
|
||||
// Return a pointer to the space.
|
||||
char *make_space(int64_t bytes) {
|
||||
int64_t available = buf_hi_ - write_cursor_;
|
||||
if (available < bytes) make_space_slow(bytes);
|
||||
return write_cursor_;
|
||||
void write_xyz(const util::XYZ &xyz) {
|
||||
write_float(xyz.x);
|
||||
write_float(xyz.y);
|
||||
write_float(xyz.z);
|
||||
}
|
||||
|
||||
// Used after calling make_space then filling the space.
|
||||
void wrote_space(int64_t bytes);
|
||||
|
||||
// Amount of data inside the buffer.
|
||||
int64_t fill() const;
|
||||
|
||||
// Get a pointer to the data.
|
||||
const char *data() const;
|
||||
|
||||
// Get entire contents as a string_view
|
||||
std::string_view view() const;
|
||||
|
||||
// Discard all data. Reset total read and write counts.
|
||||
// Frees up as much space as possible.
|
||||
void clear();
|
||||
|
||||
// Attempt to do a "readline". If there is no newline in
|
||||
// the buffer, returns empty string. If there is a newline,
|
||||
// returns a block of text that ends in newline.
|
||||
eng::string readline();
|
||||
|
||||
// Write block of bytes into the buffer.
|
||||
//
|
||||
// Caution: this function doesn't write the length!
|
||||
// It just writes the bytes.
|
||||
//
|
||||
void write_bytes(const char *bytes, int64_t len);
|
||||
void write_bytes(std::string_view s);
|
||||
|
||||
// Read a block of bytes from the buffer.
|
||||
//
|
||||
// Caution: the pointer returned is a pointer to the stream's buffer. It is
|
||||
// only valid until you mutate the buffer. Throws StreamEof if the specified
|
||||
// number of bytes aren't present.
|
||||
//
|
||||
const char *read_bytes(int64_t bytes);
|
||||
|
||||
// Copy bytes from the StreamBuffer into an external buffer.
|
||||
//
|
||||
// Returns true if the bytes were successfully read.
|
||||
//
|
||||
void read_bytes_into(char *target, int64_t len);
|
||||
|
||||
// Read a string as a string_view.
|
||||
//
|
||||
std::string_view read_string_view_limit(uint64_t limit);
|
||||
std::string_view read_string_view() { return read_string_view_limit(0x1000000); }
|
||||
|
||||
// Read and write larger types.
|
||||
//
|
||||
// Throws StreamEof if the specified number of bytes aren't present.
|
||||
// Read string with a length limit will throw 'StreamCorruption' if the
|
||||
// length is too long.
|
||||
//
|
||||
void write_xyz(const util::XYZ &xyz);
|
||||
void write_dxyz(const util::DXYZ &xyz);
|
||||
util::XYZ read_xyz();
|
||||
util::DXYZ read_dxyz();
|
||||
|
||||
void write_hashvalue(const util::HashValue &hv);
|
||||
util::HashValue read_hashvalue();
|
||||
|
||||
// Overwrite values previously written to the buffer.
|
||||
//
|
||||
// See the comment at the top of this file for an explanation.
|
||||
//
|
||||
void overwrite_int8(int64_t write_count_after, int64_t v);
|
||||
void overwrite_int16(int64_t write_count_after, int64_t v);
|
||||
void overwrite_int32(int64_t write_count_after, int64_t v);
|
||||
void overwrite_int64(int64_t write_count_after, int64_t v);
|
||||
void overwrite_uint8(int64_t write_count_after, uint64_t v);
|
||||
void overwrite_uint16(int64_t write_count_after, uint64_t v);
|
||||
void overwrite_uint32(int64_t write_count_after, uint64_t v);
|
||||
void overwrite_uint64(int64_t write_count_after, uint64_t v);
|
||||
|
||||
// This function checks to see if the buffer is empty.
|
||||
bool empty();
|
||||
|
||||
// Verify that the buffer is empty, if not, throw StreamCorruption.
|
||||
void verify_empty();
|
||||
|
||||
// Make sure the specified number of bytes are available to read.
|
||||
void check_available(int64_t bytes) {
|
||||
int64_t avail = write_cursor_ - read_cursor_;
|
||||
if (avail < bytes) {
|
||||
throw StreamEof();
|
||||
}
|
||||
void write_dxyz(const util::DXYZ &xyz) {
|
||||
write_double(xyz.x);
|
||||
write_double(xyz.y);
|
||||
write_double(xyz.z);
|
||||
}
|
||||
|
||||
// Rewind the read cursor to a previous position.
|
||||
void unread_to(int64_t total_reads);
|
||||
|
||||
// Rewind the write cursor to a previous position.
|
||||
void unwrite_to(int64_t total_writes);
|
||||
|
||||
// Copy the entire contents of this streambuffer into another one.
|
||||
void copy_into(StreamBuffer *sb);
|
||||
void write_hashvalue(const util::HashValue &h) {
|
||||
write_uint64(h.first);
|
||||
write_uint64(h.second);
|
||||
}
|
||||
|
||||
// Transfer the entire contents of this streambuffer into another one.
|
||||
void transfer_into(StreamBuffer *sb);
|
||||
util::XYZ read_xyz() {
|
||||
float x = read_float();
|
||||
float y = read_float();
|
||||
float z = read_float();
|
||||
return util::XYZ(x, y, z);
|
||||
}
|
||||
|
||||
// Compare the contents of this streambuffer to another one.
|
||||
bool contents_equal(const StreamBuffer *sb) const;
|
||||
util::DXYZ read_dxyz() {
|
||||
double x = read_double();
|
||||
double y = read_double();
|
||||
double z = read_double();
|
||||
return util::DXYZ(x, y, z);
|
||||
}
|
||||
|
||||
// Throw a StreamCorruption exception.
|
||||
void raise_truncated() { throw StreamCorruption(); }
|
||||
void raise_string_too_long() { throw StreamCorruption(); }
|
||||
|
||||
// This is for unit testing.
|
||||
bool layout_is(int64_t a, int64_t b, int64_t c);
|
||||
util::HashValue read_hashvalue() {
|
||||
uint64_t f = read_uint64();
|
||||
uint64_t s = read_uint64();
|
||||
return util::HashValue(f, s);
|
||||
}
|
||||
|
||||
private:
|
||||
// Start and end of the allocated block.
|
||||
char *buf_lo_;
|
||||
char *buf_hi_;
|
||||
bool contents_equal(const StreamBuffer *sb) {
|
||||
return view() == sb->view();
|
||||
}
|
||||
|
||||
// The write and read cursors.
|
||||
char *write_cursor_;
|
||||
char *read_cursor_;
|
||||
|
||||
// Number of bytes read before buffer was last aligned.
|
||||
int64_t pre_read_count_;
|
||||
|
||||
// True if we own this buffer.
|
||||
bool owned_;
|
||||
|
||||
// True if we're not allowed to expand this buffer.
|
||||
bool fixed_size_;
|
||||
|
||||
// Initialize with a new buffer.
|
||||
void init(bool fixed, bool owned, char *buf, int64_t size);
|
||||
|
||||
// Function that resizes the buffer during make_space operations.
|
||||
void make_space_slow(int64_t bytes);
|
||||
|
||||
// Implementation for the overwrite_int functions.
|
||||
char *get_overwrite(int64_t size, int64_t write_count_after);
|
||||
void copy_into(StreamBuffer *sb) {
|
||||
sb->write_bytes(view());
|
||||
}
|
||||
};
|
||||
|
||||
// Use a streambuffer as a lua_writer.
|
||||
|
||||
Reference in New Issue
Block a user