Use std::optional rather than sentinel values

This commit is contained in:
Chris Thrasher 2024-04-28 21:53:11 -06:00
parent 8acb9d9ab1
commit de8430bb29
19 changed files with 219 additions and 191 deletions

View File

@ -931,9 +931,10 @@ public:
return;
}
std::vector<std::uint32_t> buffer(static_cast<std::size_t>(file.getSize()) / sizeof(std::uint32_t));
const auto fileSize = file.getSize().value();
std::vector<std::uint32_t> buffer(fileSize / sizeof(std::uint32_t));
if (file.read(buffer.data(), file.getSize()) != file.getSize())
if (file.read(buffer.data(), fileSize) != file.getSize())
{
vulkanAvailable = false;
return;
@ -959,9 +960,10 @@ public:
return;
}
std::vector<std::uint32_t> buffer(static_cast<std::size_t>(file.getSize()) / sizeof(std::uint32_t));
const auto fileSize = file.getSize().value();
std::vector<std::uint32_t> buffer(fileSize / sizeof(std::uint32_t));
if (file.read(buffer.data(), file.getSize()) != file.getSize())
if (file.read(buffer.data(), fileSize) != file.getSize())
{
vulkanAvailable = false;
return;

View File

@ -111,36 +111,36 @@ public:
/// \param data Buffer where to copy the read data
/// \param size Desired number of bytes to read
///
/// \return The number of bytes actually read, or -1 on error
/// \return The number of bytes actually read, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::int64_t read(void* data, std::int64_t size) override;
[[nodiscard]] std::optional<std::size_t> read(void* data, std::size_t size) override;
////////////////////////////////////////////////////////////
/// \brief Change the current reading position
///
/// \param position The position to seek to, from the beginning
///
/// \return The position actually sought to, or -1 on error
/// \return The position actually sought to, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::int64_t seek(std::int64_t position) override;
[[nodiscard]] std::optional<std::size_t> seek(std::size_t position) override;
////////////////////////////////////////////////////////////
/// \brief Get the current reading position in the stream
///
/// \return The current position, or -1 on error.
/// \return The current position, or `std::nullopt` on error.
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::int64_t tell() override;
[[nodiscard]] std::optional<std::size_t> tell() override;
////////////////////////////////////////////////////////////
/// \brief Return the size of the stream
///
/// \return The total number of bytes available in the stream, or -1 on error
/// \return The total number of bytes available in the stream, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
std::int64_t getSize() override;
std::optional<std::size_t> getSize() override;
private:
////////////////////////////////////////////////////////////

View File

@ -31,6 +31,8 @@
#include <SFML/System/Export.hpp>
#include <optional>
#include <cstdint>
@ -58,36 +60,36 @@ public:
/// \param data Buffer where to copy the read data
/// \param size Desired number of bytes to read
///
/// \return The number of bytes actually read, or -1 on error
/// \return The number of bytes actually read, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] virtual std::int64_t read(void* data, std::int64_t size) = 0;
[[nodiscard]] virtual std::optional<std::size_t> read(void* data, std::size_t size) = 0;
////////////////////////////////////////////////////////////
/// \brief Change the current reading position
///
/// \param position The position to seek to, from the beginning
///
/// \return The position actually sought to, or -1 on error
/// \return The position actually sought to, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] virtual std::int64_t seek(std::int64_t position) = 0;
[[nodiscard]] virtual std::optional<std::size_t> seek(std::size_t position) = 0;
////////////////////////////////////////////////////////////
/// \brief Get the current reading position in the stream
///
/// \return The current position, or -1 on error.
/// \return The current position, or `std::nullopt` on error.
///
////////////////////////////////////////////////////////////
[[nodiscard]] virtual std::int64_t tell() = 0;
[[nodiscard]] virtual std::optional<std::size_t> tell() = 0;
////////////////////////////////////////////////////////////
/// \brief Return the size of the stream
///
/// \return The total number of bytes available in the stream, or -1 on error
/// \return The total number of bytes available in the stream, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
virtual std::int64_t getSize() = 0;
virtual std::optional<std::size_t> getSize() = 0;
};
} // namespace sf
@ -119,13 +121,13 @@ public:
///
/// [[nodiscard]] bool open(const std::filesystem::path& filename);
///
/// [[nodiscard]] std::int64_t read(void* data, std::int64_t size);
/// [[nodiscard]] std::optional<std::size_t> read(void* data, std::size_t size);
///
/// [[nodiscard]] std::int64_t seek(std::int64_t position);
/// [[nodiscard]] std::optional<std::size_t> seek(std::size_t position);
///
/// [[nodiscard]] std::int64_t tell();
/// [[nodiscard]] std::optional<std::size_t> tell();
///
/// std::int64_t getSize();
/// std::optional<std::size_t> getSize();
///
/// private:
///

View File

@ -64,44 +64,44 @@ public:
/// \param data Buffer where to copy the read data
/// \param size Desired number of bytes to read
///
/// \return The number of bytes actually read, or -1 on error
/// \return The number of bytes actually read, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::int64_t read(void* data, std::int64_t size) override;
[[nodiscard]] std::optional<std::size_t> read(void* data, std::size_t size) override;
////////////////////////////////////////////////////////////
/// \brief Change the current reading position
///
/// \param position The position to seek to, from the beginning
///
/// \return The position actually sought to, or -1 on error
/// \return The position actually sought to, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::int64_t seek(std::int64_t position) override;
[[nodiscard]] std::optional<std::size_t> seek(std::size_t position) override;
////////////////////////////////////////////////////////////
/// \brief Get the current reading position in the stream
///
/// \return The current position, or -1 on error.
/// \return The current position, or `std::nullopt` on error.
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::int64_t tell() override;
[[nodiscard]] std::optional<std::size_t> tell() override;
////////////////////////////////////////////////////////////
/// \brief Return the size of the stream
///
/// \return The total number of bytes available in the stream, or -1 on error
/// \return The total number of bytes available in the stream, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
std::int64_t getSize() override;
std::optional<std::size_t> getSize() override;
private:
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
const std::byte* m_data{}; //!< Pointer to the data in memory
std::int64_t m_size{}; //!< Total size of the data
std::int64_t m_offset{}; //!< Current reading position
std::size_t m_size{}; //!< Total size of the data
std::size_t m_offset{}; //!< Current reading position
};
} // namespace sf

View File

@ -213,7 +213,7 @@ void InputSoundFile::seek(std::uint64_t sampleOffset)
////////////////////////////////////////////////////////////
void InputSoundFile::seek(Time timeOffset)
{
seek(static_cast<std::uint64_t>(timeOffset.asSeconds() * static_cast<float>(m_sampleRate)) * m_channelMap.size());
seek(static_cast<std::size_t>(timeOffset.asSeconds() * static_cast<float>(m_sampleRate)) * m_channelMap.size());
}

View File

@ -58,7 +58,7 @@ std::unique_ptr<SoundFileReader> SoundFileFactory::createReaderFromFilename(cons
// Test the filename in all the registered factories
for (const auto& [fpCreate, fpCheck] : getReaderFactoryMap())
{
if (stream.seek(0) == -1)
if (!stream.seek(0).has_value())
{
err() << "Failed to seek sound stream" << std::endl;
return nullptr;
@ -84,7 +84,7 @@ std::unique_ptr<SoundFileReader> SoundFileFactory::createReaderFromMemory(const
// Test the stream for all the registered factories
for (const auto& [fpCreate, fpCheck] : getReaderFactoryMap())
{
if (stream.seek(0) == -1)
if (!stream.seek(0).has_value())
{
err() << "Failed to seek sound stream" << std::endl;
return nullptr;
@ -106,7 +106,7 @@ std::unique_ptr<SoundFileReader> SoundFileFactory::createReaderFromStream(InputS
// Test the stream for all the registered factories
for (const auto& [fpCreate, fpCheck] : getReaderFactoryMap())
{
if (stream.seek(0) == -1)
if (!stream.seek(0).has_value())
{
err() << "Failed to seek sound stream" << std::endl;
return nullptr;

View File

@ -44,16 +44,18 @@ FLAC__StreamDecoderReadStatus streamRead(const FLAC__StreamDecoder*, FLAC__byte
{
auto* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
const std::int64_t count = data->stream->read(buffer, static_cast<std::int64_t>(*bytes));
if (count > 0)
if (const std::optional count = data->stream->read(buffer, *bytes))
{
*bytes = static_cast<std::size_t>(count);
if (*count > 0)
{
*bytes = *count;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
else if (count == 0)
else
{
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
}
else
{
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
@ -64,8 +66,7 @@ FLAC__StreamDecoderSeekStatus streamSeek(const FLAC__StreamDecoder*, FLAC__uint6
{
auto* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
const std::int64_t position = data->stream->seek(static_cast<std::int64_t>(absoluteByteOffset));
if (position >= 0)
if (data->stream->seek(static_cast<std::size_t>(absoluteByteOffset)).has_value())
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
else
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
@ -75,10 +76,9 @@ FLAC__StreamDecoderTellStatus streamTell(const FLAC__StreamDecoder*, FLAC__uint6
{
auto* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
const std::int64_t position = data->stream->tell();
if (position >= 0)
if (const std::optional position = data->stream->tell())
{
*absoluteByteOffset = static_cast<FLAC__uint64>(position);
*absoluteByteOffset = *position;
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
else
@ -91,10 +91,9 @@ FLAC__StreamDecoderLengthStatus streamLength(const FLAC__StreamDecoder*, FLAC__u
{
auto* data = static_cast<sf::priv::SoundFileReaderFlac::ClientData*>(clientData);
const std::int64_t count = data->stream->getSize();
if (count >= 0)
if (const std::optional count = data->stream->getSize())
{
*streamLength = static_cast<FLAC__uint64>(count);
*streamLength = *count;
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
else

View File

@ -68,14 +68,14 @@ namespace
std::size_t readCallback(void* ptr, std::size_t size, void* data)
{
auto* stream = static_cast<sf::InputStream*>(data);
return static_cast<std::size_t>(stream->read(ptr, static_cast<std::int64_t>(size)));
return stream->read(ptr, size).value_or(-1);
}
int seekCallback(std::uint64_t offset, void* data)
{
auto* stream = static_cast<sf::InputStream*>(data);
const std::int64_t position = stream->seek(static_cast<std::int64_t>(offset));
return position < 0 ? -1 : 0;
const std::optional position = stream->seek(static_cast<std::size_t>(offset));
return position ? 0 : -1;
}
bool hasValidId3Tag(const std::uint8_t* header)
@ -92,7 +92,7 @@ bool SoundFileReaderMp3::check(InputStream& stream)
{
std::uint8_t header[10];
if (static_cast<std::size_t>(stream.read(header, static_cast<std::int64_t>(sizeof(header)))) < sizeof(header))
if (stream.read(header, sizeof(header)) != sizeof(header))
return false;
if (hasValidId3Tag(header))

View File

@ -41,29 +41,32 @@ namespace
std::size_t read(void* ptr, std::size_t size, std::size_t nmemb, void* data)
{
auto* stream = static_cast<sf::InputStream*>(data);
return static_cast<std::size_t>(stream->read(ptr, static_cast<std::int64_t>(size * nmemb)));
return stream->read(ptr, size * nmemb).value_or(-1);
}
int seek(void* data, ogg_int64_t offset, int whence)
int seek(void* data, ogg_int64_t signedOffset, int whence)
{
auto* stream = static_cast<sf::InputStream*>(data);
auto offset = static_cast<std::size_t>(signedOffset);
switch (whence)
{
case SEEK_SET:
break;
case SEEK_CUR:
offset += stream->tell();
offset += stream->tell().value();
break;
case SEEK_END:
offset = stream->getSize() - offset;
offset = stream->getSize().value() - offset;
}
return static_cast<int>(stream->seek(offset));
const std::optional position = stream->seek(offset);
return position ? static_cast<int>(*position) : -1;
}
long tell(void* data)
{
auto* stream = static_cast<sf::InputStream*>(data);
return static_cast<long>(stream->tell());
const std::optional position = stream->tell();
return position ? static_cast<long>(*position) : -1;
}
ov_callbacks callbacks = {&read, &seek, nullptr, &tell};

View File

@ -44,12 +44,12 @@ namespace
ma_result onRead(ma_decoder* decoder, void* buffer, size_t bytesToRead, size_t* bytesRead)
{
auto* stream = static_cast<sf::InputStream*>(decoder->pUserData);
const auto count = stream->read(buffer, static_cast<std::int64_t>(bytesToRead));
const std::optional count = stream->read(buffer, bytesToRead);
if (count < 0)
if (!count.has_value())
return MA_ERROR;
*bytesRead = static_cast<size_t>(count);
*bytesRead = static_cast<std::size_t>(*count);
return MA_SUCCESS;
}
@ -61,19 +61,17 @@ ma_result onSeek(ma_decoder* decoder, ma_int64 byteOffset, ma_seek_origin origin
{
case ma_seek_origin_start:
{
if (stream->seek(byteOffset) < 0)
if (!stream->seek(static_cast<std::size_t>(byteOffset)).has_value())
return MA_ERROR;
return MA_SUCCESS;
}
case ma_seek_origin_current:
{
const auto currentPosition = stream->tell();
if (currentPosition < 0)
if (!stream->tell().has_value())
return MA_ERROR;
if (stream->seek(stream->tell() + byteOffset) < 0)
if (!stream->seek(stream->tell().value() + static_cast<std::size_t>(byteOffset)).has_value())
return MA_ERROR;
return MA_SUCCESS;

View File

@ -55,13 +55,11 @@ namespace
// FreeType callbacks that operate on a sf::InputStream
unsigned long read(FT_Stream rec, unsigned long offset, unsigned char* buffer, unsigned long count)
{
const auto convertedOffset = static_cast<std::int64_t>(offset);
auto* stream = static_cast<sf::InputStream*>(rec->descriptor.pointer);
if (stream->seek(convertedOffset) == convertedOffset)
if (stream->seek(offset) == offset)
{
if (count > 0)
return static_cast<unsigned long>(
stream->read(reinterpret_cast<char*>(buffer), static_cast<std::int64_t>(count)));
return static_cast<unsigned long>(stream->read(reinterpret_cast<char*>(buffer), count).value());
else
return 0;
}
@ -244,7 +242,7 @@ std::optional<Font> Font::loadFromStream(InputStream& stream)
}
// Make sure that the stream's reading position is at the beginning
if (stream.seek(0) == -1)
if (!stream.seek(0).has_value())
{
err() << "Failed to seek font stream" << std::endl;
return std::nullopt;
@ -252,7 +250,7 @@ std::optional<Font> Font::loadFromStream(InputStream& stream)
// Prepare a wrapper for our stream, that we'll pass to FreeType callbacks
fontHandles->streamRec.base = nullptr;
fontHandles->streamRec.size = static_cast<unsigned long>(stream.getSize());
fontHandles->streamRec.size = static_cast<unsigned long>(stream.getSize().value());
fontHandles->streamRec.pos = 0;
fontHandles->streamRec.descriptor.pointer = &stream;
fontHandles->streamRec.read = &read;

View File

@ -56,13 +56,14 @@ namespace
int read(void* user, char* data, int size)
{
auto& stream = *static_cast<sf::InputStream*>(user);
return static_cast<int>(stream.read(data, size));
const std::optional count = stream.read(data, static_cast<std::size_t>(size));
return count ? static_cast<int>(*count) : -1;
}
void skip(void* user, int size)
{
auto& stream = *static_cast<sf::InputStream*>(user);
if (stream.seek(stream.tell() + size) == -1)
if (!stream.seek(stream.tell().value() + static_cast<std::size_t>(size)).has_value())
sf::err() << "Failed to seek image loader input stream" << std::endl;
}
@ -233,7 +234,7 @@ std::optional<Image> Image::loadFromMemory(const void* data, std::size_t size)
std::optional<Image> Image::loadFromStream(InputStream& stream)
{
// Make sure that the stream's reading position is at the beginning
if (stream.seek(0) == -1)
if (!stream.seek(0).has_value())
{
err() << "Failed to seek image stream" << std::endl;
return std::nullopt;

View File

@ -105,18 +105,18 @@ bool getFileContents(const std::filesystem::path& filename, std::vector<char>& b
bool getStreamContents(sf::InputStream& stream, std::vector<char>& buffer)
{
bool success = false;
const std::int64_t size = stream.getSize();
if (size > 0)
const std::optional size = stream.getSize();
if (size > std::size_t{0})
{
buffer.resize(static_cast<std::size_t>(size));
buffer.resize(*size);
if (stream.seek(0) == -1)
if (!stream.seek(0).has_value())
{
sf::err() << "Failed to seek shader stream" << std::endl;
return false;
}
const std::int64_t read = stream.read(buffer.data(), size);
const std::optional read = stream.read(buffer.data(), *size);
success = (read == size);
}
buffer.push_back('\0');

View File

@ -41,63 +41,42 @@ ResourceStream::ResourceStream(const std::filesystem::path& filename)
ActivityStates& states = getActivity();
const std::lock_guard lock(states.mutex);
m_file.reset(AAssetManager_open(states.activity->assetManager, filename.c_str(), AASSET_MODE_UNKNOWN));
assert(m_file && "Failed to initialize ResourceStream file");
}
////////////////////////////////////////////////////////////
std::int64_t ResourceStream::read(void* data, std::int64_t size)
std::optional<std::size_t> ResourceStream::read(void* data, std::size_t size)
{
if (m_file)
{
return AAsset_read(m_file.get(), data, static_cast<std::size_t>(size));
}
else
{
return -1;
}
const auto numBytesRead = AAsset_read(m_file.get(), data, size);
if (numBytesRead < 0)
return std::nullopt;
return numBytesRead;
}
////////////////////////////////////////////////////////////
std::int64_t ResourceStream::seek(std::int64_t position)
std::optional<std::size_t> ResourceStream::seek(std::size_t position)
{
if (m_file)
{
return AAsset_seek(m_file.get(), static_cast<off_t>(position), SEEK_SET);
}
else
{
return -1;
}
const auto newPosition = AAsset_seek(m_file.get(), static_cast<off_t>(position), SEEK_SET);
if (newPosition < 0)
return std::nullopt;
return newPosition;
}
////////////////////////////////////////////////////////////
std::int64_t ResourceStream::tell()
std::optional<std::size_t> ResourceStream::tell()
{
if (m_file)
{
return getSize() - AAsset_getRemainingLength(m_file.get());
}
else
{
return -1;
}
return getSize().value() - static_cast<std::size_t>(AAsset_getRemainingLength(m_file.get()));
}
////////////////////////////////////////////////////////////
std::int64_t ResourceStream::getSize()
{
if (m_file)
std::optional<std::size_t> ResourceStream::getSize()
{
return AAsset_getLength(m_file.get());
}
else
{
return -1;
}
}
////////////////////////////////////////////////////////////

View File

@ -60,36 +60,36 @@ public:
/// \param data Buffer where the asset data is copied
/// \param size Number of bytes read
///
/// \return The number of bytes actually read, or -1 on error
/// \return The number of bytes actually read, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
std::int64_t read(void* data, std::int64_t size) override;
std::optional<std::size_t> read(void* data, std::size_t size) override;
////////////////////////////////////////////////////////////
/// \brief Change the current reading position in the asset file
///
/// \param position The position to seek to, from the beginning
///
/// \return The position actually sought to, or -1 on error
/// \return The position actually sought to, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
std::int64_t seek(std::int64_t position) override;
std::optional<std::size_t> seek(std::size_t position) override;
////////////////////////////////////////////////////////////
/// \brief Get the current reading position in the asset file
///
/// \return The current position, or -1 on error.
/// \return The current position, or `std::nullopt` on error.
///
////////////////////////////////////////////////////////////
std::int64_t tell() override;
std::optional<std::size_t> tell() override;
////////////////////////////////////////////////////////////
/// \brief Return the size of the asset file
///
/// \return The total number of bytes available in the asset, or -1 on error
/// \return The total number of bytes available in the asset, or `std::nullopt` on error
///
////////////////////////////////////////////////////////////
std::int64_t getSize() override;
std::optional<std::size_t> getSize() override;
private:
////////////////////////////////////////////////////////////

View File

@ -79,78 +79,79 @@ bool FileInputStream::open(const std::filesystem::path& filename)
////////////////////////////////////////////////////////////
std::int64_t FileInputStream::read(void* data, std::int64_t size)
std::optional<std::size_t> FileInputStream::read(void* data, std::size_t size)
{
#ifdef SFML_SYSTEM_ANDROID
if (priv::getActivityStatesPtr() != nullptr)
{
if (!m_androidFile)
return -1;
return std::nullopt;
return m_androidFile->read(data, size);
}
#endif
if (!m_file)
return -1;
return static_cast<std::int64_t>(std::fread(data, 1, static_cast<std::size_t>(size), m_file.get()));
return std::nullopt;
return std::fread(data, 1, size, m_file.get());
}
////////////////////////////////////////////////////////////
std::int64_t FileInputStream::seek(std::int64_t position)
std::optional<std::size_t> FileInputStream::seek(std::size_t position)
{
#ifdef SFML_SYSTEM_ANDROID
if (priv::getActivityStatesPtr() != nullptr)
{
if (!m_androidFile)
return -1;
return std::nullopt;
return m_androidFile->seek(position);
}
#endif
if (!m_file)
return -1;
return std::nullopt;
if (std::fseek(m_file.get(), static_cast<long>(position), SEEK_SET))
return -1;
return std::nullopt;
return tell();
}
////////////////////////////////////////////////////////////
std::int64_t FileInputStream::tell()
std::optional<std::size_t> FileInputStream::tell()
{
#ifdef SFML_SYSTEM_ANDROID
if (priv::getActivityStatesPtr() != nullptr)
{
if (!m_androidFile)
return -1;
return std::nullopt;
return m_androidFile->tell();
}
#endif
if (!m_file)
return -1;
return std::ftell(m_file.get());
return std::nullopt;
const auto position = std::ftell(m_file.get());
return position < 0 ? std::nullopt : std::optional<std::size_t>(position);
}
////////////////////////////////////////////////////////////
std::int64_t FileInputStream::getSize()
std::optional<std::size_t> FileInputStream::getSize()
{
#ifdef SFML_SYSTEM_ANDROID
if (priv::getActivityStatesPtr() != nullptr)
{
if (!m_androidFile)
return -1;
return std::nullopt;
return m_androidFile->getSize();
}
#endif
if (!m_file)
return -1;
const std::int64_t position = tell();
return std::nullopt;
const auto position = tell().value();
std::fseek(m_file.get(), 0, SEEK_END);
const std::int64_t size = tell();
const std::optional size = tell();
if (seek(position) == -1)
return -1;
if (!seek(position).has_value())
return std::nullopt;
return size;
}

View File

@ -27,6 +27,8 @@
////////////////////////////////////////////////////////////
#include <SFML/System/MemoryInputStream.hpp>
#include <algorithm>
#include <cstring>
@ -36,20 +38,18 @@ namespace sf
void MemoryInputStream::open(const void* data, std::size_t sizeInBytes)
{
m_data = static_cast<const std::byte*>(data);
m_size = static_cast<std::int64_t>(sizeInBytes);
m_size = sizeInBytes;
m_offset = 0;
}
////////////////////////////////////////////////////////////
std::int64_t MemoryInputStream::read(void* data, std::int64_t size)
std::optional<std::size_t> MemoryInputStream::read(void* data, std::size_t size)
{
if (!m_data)
return -1;
const std::int64_t endPosition = m_offset + size;
const std::int64_t count = endPosition <= m_size ? size : m_size - m_offset;
return std::nullopt;
const std::size_t count = std::min(size, m_size - m_offset);
if (count > 0)
{
std::memcpy(data, m_data + m_offset, static_cast<std::size_t>(count));
@ -61,10 +61,10 @@ std::int64_t MemoryInputStream::read(void* data, std::int64_t size)
////////////////////////////////////////////////////////////
std::int64_t MemoryInputStream::seek(std::int64_t position)
std::optional<std::size_t> MemoryInputStream::seek(std::size_t position)
{
if (!m_data)
return -1;
return std::nullopt;
m_offset = position < m_size ? position : m_size;
return m_offset;
@ -72,20 +72,20 @@ std::int64_t MemoryInputStream::seek(std::int64_t position)
////////////////////////////////////////////////////////////
std::int64_t MemoryInputStream::tell()
std::optional<std::size_t> MemoryInputStream::tell()
{
if (!m_data)
return -1;
return std::nullopt;
return m_offset;
}
////////////////////////////////////////////////////////////
std::int64_t MemoryInputStream::getSize()
std::optional<std::size_t> MemoryInputStream::getSize()
{
if (!m_data)
return -1;
return std::nullopt;
return m_size;
}

View File

@ -75,10 +75,10 @@ TEST_CASE("[System] sf::FileInputStream")
SECTION("Default constructor")
{
sf::FileInputStream fileInputStream;
CHECK(fileInputStream.read(nullptr, 0) == -1);
CHECK(fileInputStream.seek(0) == -1);
CHECK(fileInputStream.tell() == -1);
CHECK(fileInputStream.getSize() == -1);
CHECK(fileInputStream.read(nullptr, 0) == std::nullopt);
CHECK(fileInputStream.seek(0) == std::nullopt);
CHECK(fileInputStream.tell() == std::nullopt);
CHECK(fileInputStream.getSize() == std::nullopt);
}
const TemporaryFile temporaryFile("Hello world");

View File

@ -16,28 +16,73 @@ TEST_CASE("[System] sf::MemoryInputStream")
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::MemoryInputStream>);
}
SECTION("Empty stream")
SECTION("Default constructor")
{
sf::MemoryInputStream mis;
CHECK(mis.read(nullptr, 0) == -1);
CHECK(mis.seek(0) == -1);
CHECK(mis.tell() == -1);
CHECK(mis.getSize() == -1);
sf::MemoryInputStream memoryInputStream;
CHECK(memoryInputStream.read(nullptr, 0) == std::nullopt);
CHECK(memoryInputStream.seek(0) == std::nullopt);
CHECK(memoryInputStream.tell() == std::nullopt);
CHECK(memoryInputStream.getSize() == std::nullopt);
}
SECTION("Open memory stream")
{
using namespace std::literals::string_view_literals;
constexpr auto memoryContents = "hello world"sv;
sf::MemoryInputStream mis;
mis.open(memoryContents.data(), sizeof(char) * memoryContents.size());
std::array<char, 32> buffer{};
CHECK(mis.read(buffer.data(), 5) == 5);
CHECK(std::string_view(buffer.data(), 5) == std::string_view(memoryContents.data(), 5));
CHECK(mis.seek(10) == 10);
CHECK(mis.tell() == 10);
CHECK(mis.getSize() == 11);
SECTION("open()")
{
sf::MemoryInputStream memoryInputStream;
memoryInputStream.open(nullptr, 0);
CHECK(memoryInputStream.tell() == std::nullopt);
CHECK(memoryInputStream.getSize() == std::nullopt);
static constexpr auto input = "hello world"sv;
memoryInputStream.open(input.data(), input.size());
CHECK(memoryInputStream.tell().value() == 0);
CHECK(memoryInputStream.getSize().value() == input.size());
}
SECTION("read()")
{
static constexpr auto input = "hello world"sv;
sf::MemoryInputStream memoryInputStream;
memoryInputStream.open(input.data(), input.size());
CHECK(memoryInputStream.tell().value() == 0);
CHECK(memoryInputStream.getSize().value() == input.size());
// Read within input
std::array<char, 32> output{};
CHECK(memoryInputStream.read(output.data(), 5).value() == 5);
CHECK(std::string_view(output.data(), 5) == "hello"sv);
CHECK(memoryInputStream.tell().value() == 5);
CHECK(memoryInputStream.getSize().value() == input.size());
// Read beyond input
CHECK(memoryInputStream.read(output.data(), 100).value() == 6);
CHECK(std::string_view(output.data(), 6) == " world"sv);
CHECK(memoryInputStream.tell().value() == 11);
CHECK(memoryInputStream.getSize().value() == input.size());
}
SECTION("seek()")
{
static constexpr auto input = "We Love SFML!"sv;
sf::MemoryInputStream memoryInputStream;
memoryInputStream.open(input.data(), input.size());
CHECK(memoryInputStream.tell().value() == 0);
CHECK(memoryInputStream.getSize().value() == input.size());
SECTION("Seek within input")
{
CHECK(memoryInputStream.seek(0).value() == 0);
CHECK(memoryInputStream.tell().value() == 0);
CHECK(memoryInputStream.seek(5).value() == 5);
CHECK(memoryInputStream.tell().value() == 5);
}
SECTION("Seek beyond input")
{
CHECK(memoryInputStream.seek(1'000).value() == input.size());
CHECK(memoryInputStream.tell().value() == input.size());
}
}
}