kge/Buffer.cc

181 lines
3.8 KiB
C++

///
/// \file Buffer.cc
/// \author kyle
/// \created 10/10/23
/// \brief Buffer implementation.
///
/// \section COPYRIGHT
/// Copyright 2023 K. Isom <kyle@imap.cc>
///
/// Permission to use, copy, modify, and/or distribute this software for
/// any purpose with or without fee is hereby granted, provided that the
/// above copyright notice and this permission notice appear in all copies.
///
/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
/// BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
/// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
/// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
/// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
/// SOFTWARE.
///
#include <optional>
#include <random>
#include <sstream>
#include <iterator>
#include "Buffer.h"
static std::string
anonymousName()
{
std::uniform_int_distribution<> dist(1000, 9999);
std::random_device randomDevice;
std::mt19937 rng(randomDevice());
std::stringstream ss;
ss << "Buffer<" << dist(rng) << ">";
return ss.str();
}
Buffer::Buffer()
: dirty(false), name(anonymousName())
{
}
Buffer::Buffer(std::string fName)
: dirty(false), name(std::move(fName))
{
}
Buffer::Buffer(std::string fName, std::string fPath)
: dirty(false), name(std::move(fName)), path(fPath)
{
if (this->path) {
this->file = OptFile (File(fPath));
}
}
Buffer::FileStatus
Buffer::Flush(OptString altPath)
{
OptOutFileStream handle = std::nullopt;
if (altPath) {
auto altFile = File(altPath.value());
handle = altFile.Flush();
} else if (this->file) {
handle = this->file.value().Flush();
} else {
// At this point, we have no alternate path to write out
// and this Buffer isn't file-backed. From this point
// forward, we can operate under the assumption that
// `this->file` is a valid file.
return Buffer::FileStatus::FileStatusVirtual;
}
auto realFile = this->file.value();
if (!handle) {
if (realFile.IsReadOnly()) {
return Buffer::FileStatus::FileStatusReadOnly;
}
if (!realFile.IsWriteable()) {
return Buffer::FileStatus::FileStatusInvalidPermissions;
}
return Buffer::FileStatus::FileStatusIOFailed;
}
/// At this point, we know we're working with a valid file handle.
auto realHandle = handle.value();
if (!realHandle->good()) {
return Buffer::FileStatus::FileStatusIOFailed;
}
for (auto line : this->contents) {
std::copy(line.begin(), line.end(),
std::ostream_iterator<uint8_t>(*realHandle, ""));
}
realHandle->flush();
realHandle->close();
delete realHandle;
this->dirty = false;
return Buffer::FileStatus::FileStatusOK;
}
Buffer::FileStatus
Buffer::Refresh()
{
if (this->IsVirtual()) {
return Buffer::FileStatus::FileStatusVirtual;
}
auto realFile = this->file.value();
auto handle = realFile.Refresh();
if (!handle) {
return FileStatus::FileStatusNonExistent;
}
auto realHandle = handle.value();
this->clearContents();
this->dirty = false; // clean slate, kiddo
/// \todo Moral quandary: if the file disappears from disk, we
/// probably want to know that, but maybe clearing the
/// contents first isn't the right move.
if (!realHandle->good()) {
delete realHandle;
return FileStatus::FileStatusIOFailed;
}
size_t currentLine = 0;
while (realHandle->good()) {
}
}
void
Buffer::ChangePath(std::string newPath)
{
this->path = OptString(std::move(newPath));
}
void
Buffer::clearContents()
{
for (auto & line : this->contents) {
line.clear();
}
this->contents.clear();
}
void
Buffer::MarkDirty()
{
if (this->dirty) {
return;
}
this->dirty = true;
}