From 9f953cc57b75e84a416faebbf6261e0d36a67d18 Mon Sep 17 00:00:00 2001 From: Olivia Appleton Date: Fri, 16 Aug 2024 01:23:19 -0500 Subject: [PATCH] Make C++ file io more idiomatic --- cplusplus/src/include/utils.hpp | 109 +++++++++--------------------- docs/conf.py | 3 +- docs/src/cplusplus/lib/macros.rst | 2 +- docs/src/cplusplus/lib/math.rst | 2 +- docs/src/cplusplus/lib/utils.rst | 6 +- 5 files changed, 39 insertions(+), 83 deletions(-) diff --git a/cplusplus/src/include/utils.hpp b/cplusplus/src/include/utils.hpp index 1212b54d..f88ccefb 100644 --- a/cplusplus/src/include/utils.hpp +++ b/cplusplus/src/include/utils.hpp @@ -1,105 +1,60 @@ #pragma once -#include + +#include +#include #include -#include -#include +#include +#include +#include + #ifdef _WIN32 -#include #include #define PATH_SEPARATOR "\\" #else -#include -#include #include #define PATH_SEPARATOR "/" #endif -char* get_parent_directory(char* path, const uint32_t levels) { -#ifdef _WIN32 - static char drive[_MAX_DRIVE]; - static char dir[_MAX_DIR]; - _splitpath(path, drive, dir, NULL, NULL); - for (uint32_t i = 0; i < levels; ++i) { - size_t len = strlen(dir); - if (len > 1 && (dir[len - 1] == '\\' || dir[len - 1] == '/')) { - dir[len - 1] = '\0'; - } - char* last_slash = strrchr(dir, '\\'); - if (!last_slash) last_slash = strrchr(dir, '/'); - if (last_slash) *last_slash = '\0'; - } - static char parent_dir[_MAX_PATH]; - snprintf(parent_dir, sizeof(parent_dir), "%s%s", drive, dir); - return parent_dir; -#else - char* dir = dirname(path); +#ifndef MAX_PATH +#define MAX_PATH 4096 +#endif + +std::string get_parent_directory(const std::string &path, const uint32_t levels) { + std::string dir = path; for (uint32_t i = 0; i < levels; ++i) { - dir = dirname(dir); - if (strcmp(dir, "/") == 0 || strcmp(dir, ".") == 0) { + size_t pos = dir.find_last_of(PATH_SEPARATOR); + if (pos != std::string::npos) { + dir.erase(pos); + } else { break; } } return dir; -#endif } -std::string get_data_file(const char *name) { - const char* start = __FILE__; -#ifdef _WIN32 +std::string get_data_file(const std::string &name) { char absolute_path[MAX_PATH]; - if (!_fullpath(absolute_path, start, MAX_PATH)) { - perror("_fullpath"); - return NULL; +#ifdef _WIN32 + if (!_fullpath(absolute_path, __FILE__, sizeof(absolute_path))) { + throw std::runtime_error("_fullpath failed with error code " + std::to_string(GetLastError())); } #else - char* absolute_path = realpath(start, NULL); - if (!absolute_path) { - perror("realpath"); - return NULL; + if (!realpath(__FILE__, absolute_path)) { + throw std::runtime_error("realpath failed with error code " + std::to_string(errno)); } #endif - char* parents_dir = get_parent_directory(absolute_path, 3); - const size_t p_len = strlen(parents_dir), - name_len = strlen(name); - char *file_path = (char *)malloc(p_len + name_len + 8); - memcpy(file_path, parents_dir, p_len); - memcpy(file_path + p_len, PATH_SEPARATOR "_data" PATH_SEPARATOR, 7); - memcpy(file_path + p_len + 7, name, name_len); - file_path[p_len + name_len + 7] = 0; - FILE* file = fopen(file_path, "r"); -#ifndef _WIN32 - free(absolute_path); -#endif -// free(parents_dir); - free(file_path); - if (!file) { - perror("fopen"); - return NULL; - } - fseek(file, 0, SEEK_END); - size_t length = ftell(file); - fseek(file, 0, SEEK_SET); - - char* buffer = (char*)malloc(length + 1); - if (!buffer) { - perror("malloc"); - fclose(file); - return NULL; + std::string file_path = get_parent_directory(std::string(absolute_path), 4) + PATH_SEPARATOR "_data" PATH_SEPARATOR + name; + std::ifstream file(file_path.c_str(), std::ios::in | std::ios::binary); + if (!file) { + throw std::runtime_error("Failed to open file: " + file_path + " with error code " + std::to_string(errno)); } - const size_t ret_code = fread(buffer, 1, length, file); - if (ret_code != length) { - if (feof(file)) - printf("Error reading %s: unexpected end of file, read %" PRIu64 " of %" PRIu64 " bytes expected\n", name, (uint64_t)ret_code, (uint64_t)length); - else if (ferror(file)) - perror("Error reading data file"); + std::ostringstream content_stream; + content_stream << file.rdbuf(); + if (!file) { + throw std::runtime_error("Error reading file: " + file_path + " with error code " + std::to_string(errno)); } - buffer[length] = 0; - fclose(file); - - std::string ret(buffer); - free(buffer); - return ret; + return content_stream.str(); } diff --git a/docs/conf.py b/docs/conf.py index 595362b6..cfaea0f8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -227,8 +227,9 @@ def setup(app): labels = [lang[0] for lang in langs] sizes = [float(lang[1]) for lang in langs] counts = [countfiles(lang) for lang in labels] + size = max(10, len(labels)) colormap = plt.get_cmap('tab10' if len(labels) <= 10 else 'tab20') - colors = [colormap(idx / len(labels)) for idx, _ in enumerate(labels)] + colors = [colormap(idx / size) for idx, _ in enumerate(labels)] _, ax = plt.subplots() ax.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', labeldistance=None, pctdistance=0.85) plt.legend(title='Languages', loc='right', bbox_to_anchor=(1,0.5), bbox_transform=plt.gcf().transFigure) diff --git a/docs/src/cplusplus/lib/macros.rst b/docs/src/cplusplus/lib/macros.rst index 1ec65874..2c6e560f 100644 --- a/docs/src/cplusplus/lib/macros.rst +++ b/docs/src/cplusplus/lib/macros.rst @@ -44,6 +44,6 @@ View source code :source:`cplusplus/src/include/macros.hpp` .. c:namespace-pop:: -.. literalinclude:: ../../../../cplusplus/src/include/macros.h +.. literalinclude:: ../../../../cplusplus/src/include/macros.hpp :language: C++ :linenos: diff --git a/docs/src/cplusplus/lib/math.rst b/docs/src/cplusplus/lib/math.rst index 3137abd7..be885a77 100644 --- a/docs/src/cplusplus/lib/math.rst +++ b/docs/src/cplusplus/lib/math.rst @@ -30,6 +30,6 @@ Includes .. c:namespace-pop:: -.. literalinclude:: ../../../../cplusplus/src/include/math.h +.. literalinclude:: ../../../../cplusplus/src/include/math.hpp :language: C++ :linenos: diff --git a/docs/src/cplusplus/lib/utils.rst b/docs/src/cplusplus/lib/utils.rst index ae46bfa8..beadae4e 100644 --- a/docs/src/cplusplus/lib/utils.rst +++ b/docs/src/cplusplus/lib/utils.rst @@ -5,15 +5,15 @@ View source code :source:`cplusplus/src/include/utils.hpp` .. cpp:namespace-push:: utils -.. cpp:function:: std::string get_data_file(const char *name) +.. cpp:function:: std::string get_data_file(const std::string name) Return a character array containing the whole contents of a file found in _data. -.. cpp:function:: char *get_parent_directory(const char *name, const uint32_t levels) +.. cpp:function:: std::string get_parent_directory(const std::string &path, uint32_t levels) .. cpp:namespace-pop:: -.. literalinclude:: ../../../../cplusplus/src/include/utils.h +.. literalinclude:: ../../../../cplusplus/src/include/utils.hpp :language: C++ :linenos: