Skip to content

Commit

Permalink
Add ReadExact/TryReadExact
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexMax committed Mar 3, 2024
1 parent 3fb94d7 commit e760473
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 47 deletions.
1 change: 0 additions & 1 deletion include/lexio/bufreader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include "./core.hpp"

#include <memory>
#include <stdexcept>

namespace LexIO
{
Expand Down
52 changes: 51 additions & 1 deletion include/lexio/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
#include <cstdint>
#include <cstring>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>

Expand Down Expand Up @@ -1038,9 +1039,58 @@ LEXIO_FORCEINLINE size_t Read(BYTE (&outArray)[N], const ReaderRef &reader)
return Read(outArray, reader, N);
}

/**
* @brief Read data from the current offset, inserting it into the passed
* buffer. Calls LexIO::RawRead as many times as necessary to fill
* the output buffer, throwing an exception if not enough bytes could
* be read.
*
* @param outDest Pointer to starting byte of output buffer.
* @param reader Reader to operate on.
* @param count Number of bytes to read.
* @throws std::runtime_error if stream encountered an EOF-like condition before
* enough bytes could be read, or if an error with the read operation
* was encountered.
*/
template <typename BYTE, typename = std::enable_if_t<!Detail::IsConstV<BYTE> && sizeof(BYTE) == 1>>
inline void ReadExact(BYTE *outDest, const ReaderRef &reader, size_t count)
{
uint8_t *dest = reinterpret_cast<uint8_t *>(outDest);
size_t offset = 0, remain = count;
while (offset != count)
{
const size_t read = reader.LexRead(dest + offset, remain);
if (read == 0)
{
throw std::runtime_error("could not read exact number of bytes");
}

offset += read;
remain -= read;
}
}

/**
* @brief Read data from the current offset, inserting it into the passed
* buffer. Calls LexIO::RawRead as many times as necessary to fill
* the output buffer, throwing an exception if not enough bytes could
* be read.
*
* @param outArray Output buffer array.
* @param reader Reader to operate on.
* @throws std::runtime_error if stream encountered an EOF-like condition before
* enough bytes could be read, or if an error with the read operation
* was encountered.
*/
template <typename BYTE, size_t N, typename = std::enable_if_t<!Detail::IsConstV<BYTE> && sizeof(BYTE) == 1>>
LEXIO_FORCEINLINE void ReadExact(BYTE (&outArray)[N], const ReaderRef &reader)
{
ReadExact(outArray, reader, N);
}

/**
* @brief Get the current contents of the buffer.
*
*
* @details LexIO::FillBuffer(0) should NEVER throw an exception.
*
* @param bufReader BufferedReader to operate on.
Expand Down
1 change: 0 additions & 1 deletion include/lexio/serialize/float.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#pragma once

#include "./tryfloat.hpp"
#include <stdexcept>

namespace LexIO
{
Expand Down
7 changes: 1 addition & 6 deletions include/lexio/serialize/int.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include "../core.hpp"

#include "./tryint.hpp"
#include <stdexcept>

namespace LexIO
{
Expand All @@ -41,11 +40,7 @@ namespace LexIO
inline uint8_t ReadU8(const ReaderRef &reader)
{
uint8_t buf[sizeof(uint8_t)] = {0};
const size_t count = Read(buf, reader);
if (count != sizeof(buf))
{
throw std::runtime_error("could not read");
}
ReadExact(buf, reader);
return buf[0];
}

Expand Down
2 changes: 0 additions & 2 deletions include/lexio/serialize/tryfloat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

#include "./tryint.hpp"

#include <stdexcept>

namespace LexIO
{

Expand Down
39 changes: 11 additions & 28 deletions include/lexio/serialize/tryint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@

#pragma once

#include "../core.hpp"
#include "../try.hpp"

#include <cstring>
#include <stdexcept>

namespace LexIO
{
Expand All @@ -38,23 +37,15 @@ namespace LexIO
* @param reader Reader to read from.
* @return True if the read was successful.
*/
inline bool TryReadU8(uint8_t &out, const ReaderRef &reader)
inline bool TryReadU8(uint8_t &out, const ReaderRef &reader) noexcept
{
try
{
uint8_t buf[sizeof(uint8_t)] = {0};
const size_t count = Read(buf, reader);
if (count != sizeof(buf))
{
return false;
}
out = buf[0];
return true;
}
catch (std::runtime_error &)
uint8_t buf[sizeof(uint8_t)] = {0};
if (!TryReadExact(buf, reader))
{
return false;
}
out = buf[0];
return true;
}

/**
Expand Down Expand Up @@ -87,23 +78,15 @@ inline bool TryWriteU8(const WriterRef &writer, uint8_t value)
* @param reader Reader to read from.
* @return True if the read was successful.
*/
inline bool TryRead8(int8_t &out, const ReaderRef &reader)
inline bool TryRead8(int8_t &out, const ReaderRef &reader) noexcept
{
try
{
uint8_t buf[sizeof(uint8_t)] = {0};
const size_t count = Read(buf, reader);
if (count != sizeof(buf))
{
return false;
}
out = int8_t(buf[0]);
return true;
}
catch (std::runtime_error &)
uint8_t buf[sizeof(uint8_t)] = {0};
if (!TryReadExact(buf, reader))
{
return false;
}
out = int8_t(buf[0]);
return true;
}

/**
Expand Down
1 change: 0 additions & 1 deletion include/lexio/serialize/varint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#pragma once

#include "./tryvarint.hpp"
#include <stdexcept>

namespace LexIO
{
Expand Down
2 changes: 0 additions & 2 deletions include/lexio/stream/file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

#include "../core.hpp"

#include <stdexcept>

namespace LexIO
{

Expand Down
1 change: 0 additions & 1 deletion include/lexio/stream/vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

#include "../core.hpp"

#include <stdexcept>
#include <vector>

namespace LexIO
Expand Down
2 changes: 0 additions & 2 deletions include/lexio/stream/view.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

#include "../core.hpp"

#include <stdexcept>

namespace LexIO
{

Expand Down
62 changes: 61 additions & 1 deletion include/lexio/try.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace LexIO
namespace Detail
{

std::exception_ptr &LastError() noexcept
inline std::exception_ptr &LastError() noexcept
{
static thread_local std::exception_ptr ex;
return ex;
Expand Down Expand Up @@ -301,6 +301,66 @@ LEXIO_FORCEINLINE bool TryRead(size_t &outActual, BYTE (&outArray)[N], const Rea
return TryRead(outActual, outArray, reader, N);
}

/**
* @brief Read data from the current offset, inserting it into the passed
* buffer. Calls LexIO::RawRead as many times as necessary to fill
* the output buffer, returning failure if not enough bytes could
* be read.
*
* @param outDest Pointer to starting byte of output buffer.
* @param reader Reader to operate on.
* @param count Number of bytes to read.
* @return True if successful, false if stream encountered an EOF-like condition
* before enough bytes could be read, or if an error with the read
* operation was encountered. To get specific error, call
* LexIO::ThrowLastError.
*/
template <typename BYTE, typename = std::enable_if_t<!Detail::IsConstV<BYTE> && sizeof(BYTE) == 1>>
inline bool TryReadExact(BYTE *outDest, const ReaderRef &reader, size_t count) noexcept
{
try
{
uint8_t *dest = reinterpret_cast<uint8_t *>(outDest);
size_t offset = 0, remain = count;
while (offset != count)
{
const size_t read = reader.LexRead(dest + offset, remain);
if (read == 0)
{
throw std::runtime_error("could not read exact number of bytes");
}

offset += read;
remain -= read;
}
return true;
}
catch (...)
{
SetLastError(std::current_exception());
return false;
}
}

/**
* @brief Read data from the current offset, inserting it into the passed
* buffer. Calls LexIO::RawRead as many times as necessary to fill
* the output buffer, returning failure if not enough bytes could
* be read.
*
* @param outArray Output buffer array.
* @param reader Reader to operate on.
* @return True if successful, false if stream encountered an EOF-like condition
* before enough bytes could be read, or if an error with the read
* operation was encountered. To get specific error, call
* LexIO::ThrowLastError.
*/
template <typename BYTE, size_t N, typename = std::enable_if_t<!Detail::IsConstV<BYTE> && sizeof(BYTE) == 1>>
LEXIO_FORCEINLINE bool TryReadExact(BYTE (&outArray)[N], const ReaderRef &reader) noexcept
{
return TryReadExact(outArray, reader, N);
}

/**
* @brief Write a buffer of data at the current offset. Calls LexIO::RawWrite
* as many times as necessary to write the entire buffer unless EOF
Expand Down
1 change: 0 additions & 1 deletion tests/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

#include <cstring>
#include <iterator>
#include <stdexcept>

#include "config.h"

Expand Down

0 comments on commit e760473

Please sign in to comment.