/// /// \file Buffer.cc /// \author kyle /// \created 10/10/23 /// \brief Buffer implementation. /// /// \section COPYRIGHT /// Copyright 2023 K. Isom /// /// 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 #include #include #include #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(*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; }