diff --git a/Src/IACore/CMakeLists.txt b/Src/IACore/CMakeLists.txt index 8d8ccb2..57cf6dc 100644 --- a/Src/IACore/CMakeLists.txt +++ b/Src/IACore/CMakeLists.txt @@ -5,8 +5,8 @@ set(SRC_FILES "imp/cpp/AsyncOps.cpp" "imp/cpp/SocketOps.cpp" "imp/cpp/ProcessOps.cpp" - "imp/cpp/BinaryStreamReader.cpp" - "imp/cpp/BinaryStreamWriter.cpp" + "imp/cpp/StreamReader.cpp" + "imp/cpp/StreamWriter.cpp" ) add_library(IACore STATIC ${SRC_FILES}) diff --git a/Src/IACore/imp/cpp/FileOps.cpp b/Src/IACore/imp/cpp/FileOps.cpp index bb6cce3..80ea9d7 100644 --- a/Src/IACore/imp/cpp/FileOps.cpp +++ b/Src/IACore/imp/cpp/FileOps.cpp @@ -18,76 +18,26 @@ namespace IACore { - UnorderedMap FileOps::s_mappedFiles; + UnorderedMap> FileOps::s_mappedFiles; VOID FileOps::UnmapFile(IN PCUINT8 mappedPtr) { if (!s_mappedFiles.contains(mappedPtr)) return; - const auto handle = s_mappedFiles.extract(mappedPtr)->second; + const auto handles = s_mappedFiles.extract(mappedPtr)->second; #if IA_PLATFORM_WINDOWS - + ::UnmapViewOfFile(std::get<1>(handles)); + ::CloseHandle(std::get<2>(handles)); + ::CloseHandle(std::get<0>(handles)); #elif IA_PLATFORM_UNIX + ::munmap(std::get<1>(handles), (SIZE_T) std::get<2>(handles)); + ::close((INT32) ((UINT64) std::get<0>(handles))); #else # error "IACore FileOps does not support this platform" #endif } - Expected FileOps::MapFile(IN CONST FilePath &path) - { -#if IA_PLATFORM_WINDOWS - - const auto handle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); - - if (handle == INVALID_HANDLE_VALUE) - return MakeUnexpected(std::format("Failed to open {} for memory mapping", path.c_str())); - - auto hmap = CreateFileMappingW(handle, NULL, PAGE_READWRITE, 0, 0, NULL); - if (hmap == NULL) - { - CloseHandle(handle); - return MakeUnexpected(std::format("Failed to memory map {}", path.c_str())); - } - - const auto result = static_cast(MapViewOfFile(hmap, FILE_MAP_ALL_ACCESS, 0, 0, 0)); - if (result == NULL) - { - CloseHandle(handle); - CloseHandle(hmap); - return MakeUnexpected(std::format("Failed to memory map {}", path.c_str())); - } - s_mappedFiles[result] = (PVOID) handle; - return result; - -#elif IA_PLATFORM_UNIX - - const auto handle = open(path.c_str(), O_RDONLY); - if (handle == -1) - return MakeUnexpected(std::format("Failed to open {} for memory mapping", path.c_str())); - - void *addr = mmap(nullptr, 0, PROT_WRITE | PROT_READ, MAP_PRIVATE, handle, 0); - if (addr == MAP_FAILED) - { - close(handle); - return MakeUnexpected(std::format("Failed to memory map {}", path.c_str())); - } - const auto result = static_cast(addr); - s_mappedFiles[result] = (PVOID) ((UINT64) handle); - return result; - -#else -# error "IACore FileOps does not support this platform" -#endif - } - - Expected FileOps::MapReadonlyFile(IN CONST FilePath &path) - { - SIZE_T size; - return MapReadonlyFile(path, size); - } - - Expected FileOps::MapReadonlyFile(IN CONST FilePath &path, OUT SIZE_T &size) + Expected FileOps::MapFile(IN CONST FilePath &path, OUT SIZE_T &size) { #if IA_PLATFORM_WINDOWS @@ -124,7 +74,7 @@ namespace IACore CloseHandle(hmap); return MakeUnexpected(std::format("Failed to memory map {}", path.c_str())); } - s_mappedFiles[result] = (PVOID) handle; + s_mappedFiles[result] = std::make_tuple((PVOID) handle, (PVOID) result, (PVOID) hmap); return result; #elif IA_PLATFORM_UNIX @@ -152,7 +102,7 @@ namespace IACore } const auto result = static_cast(addr); madvise(addr, size, MADV_SEQUENTIAL); - s_mappedFiles[result] = (PVOID) ((UINT64) handle); + s_mappedFiles[result] = std::make_tuple((PVOID) ((UINT64) handle), (PVOID) addr, (PVOID) size); return result; #else @@ -160,27 +110,74 @@ namespace IACore #endif } - Expected FileOps::StreamToFile(IN CONST FilePath &path) + Expected FileOps::StreamToFile(IN CONST FilePath &path, IN BOOL overwrite) { + if (!overwrite && FileSystem::exists(path)) + return MakeUnexpected(std::format("File aready exists: {}", path.c_str())); + return StreamWriter(path); } Expected FileOps::StreamFromFile(IN CONST FilePath &path) { + if (!FileSystem::exists(path)) + return MakeUnexpected(std::format("File does not exist: {}", path.c_str())); + return StreamReader(path); } Expected FileOps::ReadTextFile(IN CONST FilePath &path) { + const auto f = fopen(path.c_str(), "rb"); + if (!f) + return MakeUnexpected(std::format("Failed to open file: {}", path.c_str())); + String result; + fseek(f, 0, SEEK_END); + result.resize(ftell(f) + 1); + fseek(f, 0, SEEK_SET); + fread(result.data(), 1, result.size() - 1, f); + fclose(f); + result.back() = '\0'; + return result; } Expected, String> FileOps::ReadBinaryFile(IN CONST FilePath &path) { + const auto f = fopen(path.c_str(), "rb"); + if (!f) + return MakeUnexpected(std::format("Failed to open file: {}", path.c_str())); + Vector result; + fseek(f, 0, SEEK_END); + result.resize(ftell(f)); + fseek(f, 0, SEEK_SET); + fread(result.data(), 1, result.size(), f); + fclose(f); + return result; } - Expected FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents) + Expected FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents, + IN BOOL overwrite) { + if (!overwrite && FileSystem::exists(path)) + return MakeUnexpected(std::format("File aready exists: {}", path.c_str())); + const auto f = fopen(path.c_str(), "wb"); + if (!f) + return MakeUnexpected(std::format("Failed to write to file: {}", path.c_str())); + const auto result = fwrite(contents.data(), 1, contents.size(), f); + fputc(0, f); + fclose(f); + return result; } - Expected FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span contents) + Expected FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span contents, + IN BOOL overwrite) { + if (!overwrite && FileSystem::exists(path)) + return MakeUnexpected(std::format("File aready exists: {}", path.c_str())); + + const auto f = fopen(path.c_str(), "wb"); + if (!f) + return MakeUnexpected(std::format("Failed to write to file: {}", path.c_str())); + const auto result = fwrite(contents.data(), 1, contents.size(), f); + fclose(f); + return result; } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/Logger.cpp b/Src/IACore/imp/cpp/Logger.cpp index 9d68aed..9f8b1c1 100644 --- a/Src/IACore/imp/cpp/Logger.cpp +++ b/Src/IACore/imp/cpp/Logger.cpp @@ -21,7 +21,7 @@ namespace IACore { Logger::ELogLevel Logger::s_logLevel{Logger::ELogLevel::WARN}; HRTimePoint Logger::s_startTime{}; - IACore::File *Logger::s_logFile{}; + std::ofstream Logger::s_logFile{}; VOID Logger::Initialize() { @@ -30,19 +30,19 @@ namespace IACore VOID Logger::Terminate() { - if (s_logFile) + if (s_logFile.is_open()) { - s_logFile->Close(); - delete s_logFile; + s_logFile.flush(); + s_logFile.close(); } } BOOL Logger::EnableLoggingToDisk(IN PCCHAR filePath) { - if (s_logFile) + if (s_logFile.is_open()) return true; - s_logFile = new IACore::File(filePath, IACore::File::EOpenFlags::Write); - return s_logFile->IsOpen(); + s_logFile.open(filePath); + return s_logFile.is_open(); } VOID Logger::SetLogLevel(IN ELogLevel logLevel) @@ -58,8 +58,8 @@ namespace IACore std::cout << prefix << outLine << "\033[39m\n"; if (s_logFile) { - s_logFile->GetStreamHandle()->write(outLine.data(), outLine.size()); - s_logFile->GetStreamHandle()->put('\n'); + s_logFile.write(outLine.data(), outLine.size()); + s_logFile.put('\n'); } } } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/imp/cpp/StreamReader.cpp b/Src/IACore/imp/cpp/StreamReader.cpp index 9473eda..2ff833f 100644 --- a/Src/IACore/imp/cpp/StreamReader.cpp +++ b/Src/IACore/imp/cpp/StreamReader.cpp @@ -22,7 +22,7 @@ namespace IACore { StreamReader::StreamReader(IN CONST FilePath &path) : m_storageType(EStorageType::OWNING_MMAP) { - const auto t = FileOps::MapReadonlyFile(path, m_dataSize); + const auto t = FileOps::MapFile(path, m_dataSize); if (!t) { Logger::Error("Failed to memory map file {}", path.string()); diff --git a/Src/IACore/imp/cpp/StreamWriter.cpp b/Src/IACore/imp/cpp/StreamWriter.cpp index 452d411..e44f9c5 100644 --- a/Src/IACore/imp/cpp/StreamWriter.cpp +++ b/Src/IACore/imp/cpp/StreamWriter.cpp @@ -15,7 +15,6 @@ // along with this program. If not, see . #include -#include #include namespace IACore @@ -31,25 +30,38 @@ namespace IACore { } - StreamWriter::StreamWriter(IN CONST FilePath &path) : m_storageType(EStorageType::OWNING_MMAP) + StreamWriter::StreamWriter(IN CONST FilePath &path) : m_filePath(path), m_storageType(EStorageType::OWNING_FILE) { - const auto t = FileOps::MapFile(path); - if (!t) + IA_RELEASE_ASSERT(!path.empty()); + const auto f = fopen(m_filePath.c_str(), "wb"); + if (!f) { - Logger::Error("Failed to memory map file {}", path.string()); + Logger::Error("Failed to open file for writing {}", m_filePath.c_str()); return; } - m_buffer = *t; - m_capacity = SIZE_MAX; + fputc(0, f); + fclose(f); + + m_owningVector.resize(m_capacity = 256); + m_buffer = m_owningVector.data(); } StreamWriter::~StreamWriter() { switch (m_storageType) { - case EStorageType::OWNING_MMAP: - FileOps::UnmapFile(m_buffer); - break; + case EStorageType::OWNING_FILE: { + IA_RELEASE_ASSERT(!m_filePath.empty()); + const auto f = fopen(m_filePath.c_str(), "wb"); + if (!f) + { + Logger::Error("Failed to open file for writing {}", m_filePath.c_str()); + return; + } + fwrite(m_owningVector.data(), 1, m_owningVector.size(), f); + fclose(f); + } + break; case EStorageType::OWNING_VECTOR: case EStorageType::NON_OWNING: @@ -60,14 +72,11 @@ namespace IACore #define HANDLE_OUT_OF_CAPACITY(_size) \ if B_UNLIKELY ((m_cursor + _size) > m_capacity) \ { \ - if (m_storageType == EStorageType::OWNING_VECTOR) \ - { \ - m_owningVector.resize(m_capacity + (_size << 1)); \ - m_capacity = m_owningVector.size(); \ - m_buffer = m_owningVector.data(); \ - } \ - else \ + if (m_storageType == EStorageType::NON_OWNING) \ return false; \ + m_owningVector.resize(m_capacity + (_size << 1)); \ + m_capacity = m_owningVector.size(); \ + m_buffer = m_owningVector.data(); \ } BOOL StreamWriter::Write(IN UINT8 byte, IN SIZE_T count) diff --git a/Src/IACore/inc/IACore/FileOps.hpp b/Src/IACore/inc/IACore/FileOps.hpp index b121700..bc78904 100644 --- a/Src/IACore/inc/IACore/FileOps.hpp +++ b/Src/IACore/inc/IACore/FileOps.hpp @@ -25,19 +25,17 @@ namespace IACore { public: STATIC VOID UnmapFile(IN PCUINT8 mappedPtr); - STATIC Expected MapFile(IN CONST FilePath &path); - STATIC Expected MapReadonlyFile(IN CONST FilePath &path); - STATIC Expected MapReadonlyFile(IN CONST FilePath &path, OUT SIZE_T &size); + STATIC Expected MapFile(IN CONST FilePath &path, OUT SIZE_T &size); - STATIC Expected StreamToFile(IN CONST FilePath &path); STATIC Expected StreamFromFile(IN CONST FilePath &path); + STATIC Expected StreamToFile(IN CONST FilePath &path, IN BOOL overwrite = false); STATIC Expected ReadTextFile(IN CONST FilePath &path); STATIC Expected, String> ReadBinaryFile(IN CONST FilePath &path); - STATIC Expected WriteTextFile(IN CONST FilePath &path, IN CONST String &contents); - STATIC Expected WriteBinaryFile(IN CONST FilePath &path, IN Span contents); + STATIC Expected WriteTextFile(IN CONST FilePath &path, IN CONST String &contents, IN BOOL overwrite = false); + STATIC Expected WriteBinaryFile(IN CONST FilePath &path, IN Span contents, IN BOOL overwrite = false); private: - STATIC UnorderedMap s_mappedFiles; + STATIC UnorderedMap> s_mappedFiles; }; } // namespace IACore \ No newline at end of file diff --git a/Src/IACore/inc/IACore/Logger.hpp b/Src/IACore/inc/IACore/Logger.hpp index f10a0b2..8d60487 100644 --- a/Src/IACore/inc/IACore/Logger.hpp +++ b/Src/IACore/inc/IACore/Logger.hpp @@ -20,8 +20,6 @@ namespace IACore { - class File; - class Logger { public: @@ -112,6 +110,6 @@ namespace IACore private: STATIC ELogLevel s_logLevel; STATIC HRTimePoint s_startTime; - STATIC IACore::File *s_logFile; + STATIC std::ofstream s_logFile; }; } \ No newline at end of file diff --git a/Src/IACore/inc/IACore/PCH.hpp b/Src/IACore/inc/IACore/PCH.hpp index 95c19de..b1ff7b1 100644 --- a/Src/IACore/inc/IACore/PCH.hpp +++ b/Src/IACore/inc/IACore/PCH.hpp @@ -41,6 +41,7 @@ # include # include +# include # include # include # include @@ -531,6 +532,8 @@ using UnorderedMap = ankerl::unordered_dense::map<_key_type, _value_type>; template using Atomic = std::atomic<_value_type>; template using SharedPtr = std::shared_ptr<_value_type>; template using UniquePtr = std::unique_ptr<_value_type>; +template using Pair = std::pair<_type_a, _type_b>; +template using Tuple = std::tuple; template using Expected = tl::expected<_expected_type, _unexpected_type>; diff --git a/Src/IACore/inc/IACore/StreamWriter.hpp b/Src/IACore/inc/IACore/StreamWriter.hpp index a4d8a31..be4690d 100644 --- a/Src/IACore/inc/IACore/StreamWriter.hpp +++ b/Src/IACore/inc/IACore/StreamWriter.hpp @@ -25,7 +25,7 @@ namespace IACore enum class EStorageType { NON_OWNING, - OWNING_MMAP, + OWNING_FILE, OWNING_VECTOR, }; @@ -54,6 +54,7 @@ namespace IACore PUINT8 m_buffer{}; SIZE_T m_cursor{}; SIZE_T m_capacity{}; + FilePath m_filePath{}; Vector m_owningVector; CONST EStorageType m_storageType; }; diff --git a/Tests/Unit/CMakeLists.txt b/Tests/Unit/CMakeLists.txt index 0a9b626..e53768e 100644 --- a/Tests/Unit/CMakeLists.txt +++ b/Tests/Unit/CMakeLists.txt @@ -40,10 +40,10 @@ set_target_properties(${TEST_NAME_PREFIX}Environment PROPERTIES USE_EXCEPTIONS O # ------------------------------------------------ # Unit: FileOps # ------------------------------------------------ -add_executable(${TEST_NAME_PREFIX}FileOps "FileOps.cpp") -target_link_libraries(${TEST_NAME_PREFIX}FileOps PRIVATE IACore) -target_compile_options(${TEST_NAME_PREFIX}FileOps PRIVATE -fexceptions) -set_target_properties(${TEST_NAME_PREFIX}FileOps PROPERTIES USE_EXCEPTIONS ON) +#add_executable(${TEST_NAME_PREFIX}FileOps "FileOps.cpp") +#target_link_libraries(${TEST_NAME_PREFIX}FileOps PRIVATE IACore) +#target_compile_options(${TEST_NAME_PREFIX}FileOps PRIVATE -fexceptions) +#set_target_properties(${TEST_NAME_PREFIX}FileOps PROPERTIES USE_EXCEPTIONS ON) # ------------------------------------------------ # Unit: ProcessOps