Template
Initial commit
This commit is contained in:
commit
d1890b6e18
16 files changed
+702
No files matched your search
@@ -0,0 +1,69 @@
|
||||
#include "file-stream.h"
|
||||
|
||||
#include "core-library/io/io-helper.h"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
core::file_stream::~file_stream()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
core::file_stream::file_stream(file_stream&& other) noexcept
|
||||
: m_file_handle(std::exchange(other.m_file_handle, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
core::file_stream& core::file_stream::operator=(file_stream&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
core::close_file(m_file_handle);
|
||||
m_file_handle = std::exchange(other.m_file_handle, nullptr);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
core::file_stream core::file_stream::open_for_reading(const std::filesystem::path& file_path)
|
||||
{
|
||||
file_stream stream{};
|
||||
stream.m_file_handle = core::open_file(file_path.string().c_str(), "rb");
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
std::string core::file_stream::file_contents_as_string(const std::filesystem::path& file_path)
|
||||
{
|
||||
file_stream stream = open_for_reading(file_path);
|
||||
return stream.read_all_as_string();
|
||||
}
|
||||
|
||||
std::string core::file_stream::read_all_as_string()
|
||||
{
|
||||
if (!m_file_handle)
|
||||
return {};
|
||||
|
||||
core::seek_file_to_end(m_file_handle);
|
||||
const std::size_t file_size = static_cast<std::size_t>(core::get_file_offset(m_file_handle));
|
||||
core::seek_file_to_beginning(m_file_handle);
|
||||
|
||||
if (file_size == 0)
|
||||
return {};
|
||||
|
||||
std::string result(file_size, '\0');
|
||||
core::read_from_file(&result[0], 1, file_size, m_file_handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void core::file_stream::close()
|
||||
{
|
||||
if (m_file_handle)
|
||||
{
|
||||
if (int result = std::fclose(m_file_handle); result != 0)
|
||||
throw std::system_error(std::error_code{result, std::system_category()});
|
||||
|
||||
m_file_handle = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <concepts>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace core {
|
||||
|
||||
class file_stream
|
||||
{
|
||||
public:
|
||||
file_stream(const file_stream&) = delete;
|
||||
file_stream& operator=(const file_stream&) = delete;
|
||||
file_stream(file_stream&&) noexcept;
|
||||
file_stream& operator=(file_stream&&);
|
||||
~file_stream();
|
||||
|
||||
static file_stream open_for_reading(const std::filesystem::path& file_path);
|
||||
static std::string file_contents_as_string(const std::filesystem::path& file_path);
|
||||
|
||||
std::string read_all_as_string();
|
||||
void close();
|
||||
|
||||
private:
|
||||
file_stream() = default;
|
||||
|
||||
FILE* m_file_handle{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "io-helper.h"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
std::FILE* core::open_file(const char* file_path, const char* mode)
|
||||
{
|
||||
std::FILE* file = std::fopen(file_path, mode);
|
||||
if (!file)
|
||||
throw std::system_error(errno, std::system_category());
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void core::seek_file_to_beginning(std::FILE* file, long offset)
|
||||
{
|
||||
const int result = std::fseek(file, offset, SEEK_SET);
|
||||
if (result != 0)
|
||||
throw std::system_error(errno, std::system_category());
|
||||
}
|
||||
|
||||
void core::seek_file_relatively(std::FILE* file, long offset)
|
||||
{
|
||||
const int result = std::fseek(file, offset, SEEK_CUR);
|
||||
if (result != 0)
|
||||
throw std::system_error(errno, std::system_category());
|
||||
}
|
||||
|
||||
void core::seek_file_to_end(std::FILE* file, long offset)
|
||||
{
|
||||
const int result = std::fseek(file, offset, SEEK_END);
|
||||
if (result != 0)
|
||||
throw std::system_error(errno, std::system_category());
|
||||
}
|
||||
|
||||
long core::get_file_offset(std::FILE* file)
|
||||
{
|
||||
const long offset = std::ftell(file);
|
||||
if (offset < 0)
|
||||
throw std::system_error(errno, std::system_category());
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
std::size_t core::read_from_file(void* buffer, std::size_t size, std::size_t count, std::FILE* file)
|
||||
{
|
||||
const std::size_t objects_read = std::fread(buffer, size, count, file);
|
||||
if (objects_read < count)
|
||||
{
|
||||
if (std::feof(file))
|
||||
throw std::runtime_error("Failed to read from file: End-of-file reached.");
|
||||
else
|
||||
throw std::runtime_error("Failed to read from file: Unknown error.");
|
||||
}
|
||||
|
||||
return objects_read;
|
||||
}
|
||||
|
||||
std::size_t core::write_to_file(const void* buffer, std::size_t size, std::size_t count, std::FILE* file)
|
||||
{
|
||||
const std::size_t objects_written = std::fwrite(buffer, size, count, file);
|
||||
if (objects_written < count)
|
||||
throw std::runtime_error("Failed to write to file.");
|
||||
|
||||
return objects_written;
|
||||
}
|
||||
|
||||
void core::close_file(std::FILE* file)
|
||||
{
|
||||
int result = std::fclose(file);
|
||||
if (result != 0)
|
||||
throw std::runtime_error("Failed to close file.");
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <cstdio>
|
||||
#include <string_view>
|
||||
|
||||
namespace core {
|
||||
|
||||
extern std::FILE* open_file(const char* file_path, const char* mode);
|
||||
extern void seek_file_to_beginning(std::FILE* file, long offset = 0);
|
||||
extern void seek_file_relatively(std::FILE* file, long offset);
|
||||
extern void seek_file_to_end(std::FILE* file, long offset = 0);
|
||||
extern long get_file_offset(std::FILE* file);
|
||||
extern std::size_t read_from_file(void* buffer, std::size_t size, std::size_t count, std::FILE* file);
|
||||
extern std::size_t write_to_file(const void* buffer, std::size_t size, std::size_t count, std::FILE* file);
|
||||
extern void close_file(std::FILE* file);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
project "cpp-core-library"
|
||||
do
|
||||
kind "StaticLib"
|
||||
location "%{_MAIN_SCRIPT_DIR}/.build"
|
||||
includedirs {"%{_MAIN_SCRIPT_DIR}"}
|
||||
files {
|
||||
"**.cpp",
|
||||
"**.h",
|
||||
}
|
||||
|
||||
filter "toolset:msc*"
|
||||
do
|
||||
defines {"_CRT_SECURE_NO_WARNINGS"}
|
||||
end
|
||||
|
||||
filter ""
|
||||
end
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include <concepts>
|
||||
|
||||
namespace core {
|
||||
|
||||
template<typename T>
|
||||
concept callable = requires { &T::operator(); };
|
||||
|
||||
template<typename T>
|
||||
struct function_traits
|
||||
{
|
||||
using return_type = void;
|
||||
using first_argument_type = void;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
requires callable<T>
|
||||
struct function_traits<T>
|
||||
{
|
||||
using return_type = typename function_traits<decltype(&T::operator())>::return_type;
|
||||
using first_argument_type = typename function_traits<decltype(&T::operator())>::first_argument_type;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Arg0, typename... Args>
|
||||
struct function_traits<Ret(Arg0, Args...)>
|
||||
{
|
||||
using return_type = typename Ret;
|
||||
using first_argument_type = typename Arg0;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Arg0, typename... Args>
|
||||
struct function_traits<Ret (*)(Arg0, Args...)>
|
||||
{
|
||||
using return_type = typename Ret;
|
||||
using first_argument_type = typename Arg0;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename Arg0, typename... Args>
|
||||
struct function_traits<Ret (Class::*)(Arg0, Args...)>
|
||||
{
|
||||
using return_type = typename Ret;
|
||||
using first_argument_type = typename Arg0;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename Arg0, typename... Args>
|
||||
struct function_traits<Ret (Class::*)(Arg0, Args...) const>
|
||||
{
|
||||
using return_type = typename Ret;
|
||||
using first_argument_type = typename Arg0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using return_type_t = typename function_traits<T>::return_type;
|
||||
|
||||
template<typename T>
|
||||
using first_argument_type_t = typename function_traits<T>::first_argument_type;
|
||||
|
||||
template<typename T, typename Arg>
|
||||
concept callable_with_converted_argument = requires(T&& callable, Arg&& arg) { callable(typename traits::first_argument_type_t<T>{arg}); };
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
#include <ranges>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace core {
|
||||
|
||||
class command_line_argument
|
||||
{
|
||||
public:
|
||||
constexpr command_line_argument(char* arg, std::span<char*> modifiers)
|
||||
: m_arg_view{arg}
|
||||
, m_modifiers{modifiers}
|
||||
{
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
requires std::invocable<F>
|
||||
void with(std::string_view arg_to_match_view, F&& function) const
|
||||
{
|
||||
if (arg_to_match_view == m_arg_view)
|
||||
std::invoke(std::forward<F>(function));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string_view m_arg_view;
|
||||
std::span<char*> m_modifiers;
|
||||
};
|
||||
|
||||
class command_line_args_view : public std::ranges::view_interface<command_line_args_view>
|
||||
{
|
||||
public:
|
||||
constexpr command_line_args_view() = default;
|
||||
|
||||
constexpr command_line_args_view(int argc, char* argv[])
|
||||
: m_argc{--argc}
|
||||
, m_application_path{argv++[0]}
|
||||
, m_argv{argv}
|
||||
{
|
||||
}
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
constexpr iterator(int argc, char** argv, int index)
|
||||
: m_argv{argv}
|
||||
, m_argc{argc}
|
||||
, m_index{index}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr iterator& operator++()
|
||||
{
|
||||
++m_index;
|
||||
|
||||
while (m_index < m_argc)
|
||||
{
|
||||
const std::string_view arg_view{m_argv[m_index]};
|
||||
if (arg_view.starts_with("--"))
|
||||
m_modifier_start_index = m_index++;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr command_line_argument operator*() const
|
||||
{
|
||||
if (m_modifier_start_index != -1)
|
||||
return command_line_argument{m_argv[m_index], std::span<char*>(&m_argv[m_modifier_start_index], &m_argv[m_index])};
|
||||
else
|
||||
return command_line_argument{m_argv[m_index], {}};
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const iterator& other) const { return m_argv != other.m_argv || m_index != other.m_index; }
|
||||
|
||||
private:
|
||||
char** m_argv;
|
||||
int m_argc;
|
||||
int m_index;
|
||||
int m_modifier_start_index{-1};
|
||||
};
|
||||
|
||||
constexpr auto&& appliation_path() const { return m_application_path; }
|
||||
|
||||
constexpr iterator begin() const { return iterator{m_argc, m_argv, 0}; }
|
||||
constexpr iterator end() const { return iterator{m_argc, m_argv, m_argc}; }
|
||||
constexpr std::size_t size() const { return static_cast<std::size_t>(m_argc); }
|
||||
|
||||
private:
|
||||
int m_argc{};
|
||||
char* m_application_path{};
|
||||
char** m_argv{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include "core-library/views/trim-view.h"
|
||||
|
||||
namespace core {
|
||||
|
||||
template<std::ranges::forward_range Range>
|
||||
requires requires(Range&& range) {
|
||||
(void)range.empty();
|
||||
(void)trim_view{(*std::begin(range))};
|
||||
}
|
||||
class trim_elements_view : public std::ranges::view_interface<trim_elements_view<Range>>
|
||||
{
|
||||
public:
|
||||
constexpr trim_elements_view(Range range)
|
||||
: m_range(std::move(range))
|
||||
{
|
||||
}
|
||||
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
using base_t = std::ranges::iterator_t<Range>;
|
||||
|
||||
constexpr iterator(base_t base, base_t end)
|
||||
: m_base{base}
|
||||
, m_end{end}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr bool operator!=(iterator other) const { return m_base != other.m_base; }
|
||||
constexpr auto operator*() const { return trim_view{*m_base}; }
|
||||
|
||||
constexpr iterator& operator++()
|
||||
{
|
||||
// Skip empty elements
|
||||
while (++m_base != m_end && std::ranges::empty(**this)) {}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
base_t m_base;
|
||||
base_t m_end;
|
||||
};
|
||||
|
||||
constexpr auto begin() { return iterator{std::begin(m_range), std::end(m_range)}; }
|
||||
constexpr auto end() { return iterator{std::end(m_range), std::end(m_range)}; }
|
||||
|
||||
private:
|
||||
Range m_range{};
|
||||
};
|
||||
|
||||
constexpr view_closure<trim_elements_view> trim_elements{};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include "core-library/views/view-closure.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
namespace core {
|
||||
|
||||
template<std::ranges::forward_range Range>
|
||||
requires requires(Range&& range) {
|
||||
*std::begin(range) == ' '; // Comparable with char literals.
|
||||
}
|
||||
class trim_view : public std::ranges::view_interface<trim_view<Range>>
|
||||
{
|
||||
public:
|
||||
constexpr explicit trim_view(Range range)
|
||||
: m_range(std::move(range))
|
||||
{
|
||||
}
|
||||
|
||||
static constexpr bool is_space(auto&& c)
|
||||
{
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\0';
|
||||
}
|
||||
|
||||
constexpr auto begin()
|
||||
{
|
||||
auto it = std::begin(m_range);
|
||||
while (it != std::end(m_range) && is_space(*it))
|
||||
++it;
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr auto end()
|
||||
{
|
||||
auto nonspace_end = std::end(m_range);
|
||||
|
||||
for (auto it = std::begin(m_range); it != std::end(m_range);)
|
||||
{
|
||||
if (!is_space(*it++))
|
||||
nonspace_end = it;
|
||||
}
|
||||
|
||||
return nonspace_end;
|
||||
}
|
||||
|
||||
private:
|
||||
Range m_range{};
|
||||
};
|
||||
|
||||
constexpr view_closure<trim_view> trim{};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include <ranges>
|
||||
|
||||
namespace core {
|
||||
|
||||
template<template<typename> typename ViewTemplate>
|
||||
class view_closure : public std::ranges::range_adaptor_closure<view_closure<ViewTemplate>>
|
||||
{
|
||||
public:
|
||||
template<std::ranges::viewable_range Range>
|
||||
constexpr auto operator()(Range&& range) const
|
||||
requires requires { ViewTemplate<std::views::all_t<Range>>{std::forward<Range>(range)}; }
|
||||
{
|
||||
return ViewTemplate<std::views::all_t<Range>>{std::forward<Range>(range)};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user