Template
Initial commit
This commit is contained in:
commit
d1890b6e18
16 files changed
+702
No files matched your search
+118
@@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
BasedOnStyle: Microsoft
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
AlignConsecutiveAssignments: true
|
||||||
|
AlignConsecutiveBitFields: true
|
||||||
|
AlignConsecutiveDeclarations: true
|
||||||
|
AlignConsecutiveMacros: true
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: AlignAfterOperator
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLambdasOnASingleLine: Inline
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: true
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: true
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: true
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
AfterExternBlock: true
|
||||||
|
BeforeCatch: true
|
||||||
|
BeforeElse: true
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: true
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakAfterJavaFieldAnnotations: true
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakInheritanceList: BeforeComma
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 0
|
||||||
|
CompactNamespaces: true
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 0
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DeriveLineEnding: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^<.*\.h>'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 3
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentExternBlock: NoIndent
|
||||||
|
IndentGotoLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertTrailingCommas: None
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Never
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCBreakBeforeNestedBlockParam: true
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: false
|
||||||
|
PenaltyBreakAssignment: 0
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 0
|
||||||
|
PenaltyBreakComment: 0
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakString: 0
|
||||||
|
PenaltyBreakTemplateDeclaration: 0
|
||||||
|
PenaltyExcessCharacter: 0
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 0
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: true
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Latest
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: AlignWithSpaces
|
||||||
|
...
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
# see https://github.com/CppCXY/EmmyLuaCodeStyle
|
||||||
|
[*.lua]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
trailing_table_separator = smart
|
||||||
|
call_arg_parentheses = remove_string_only
|
||||||
|
space_around_table_field_list = false
|
||||||
|
line_space_after_do_statement = min(2)
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Intermediate files
|
||||||
|
.build/
|
||||||
|
.obj/
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Generated project files
|
||||||
|
*.sln*
|
||||||
|
|
||||||
|
# Output files
|
||||||
|
/bin/
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#include <core-library/views/command-line-args-view.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
void print_help(std::filesystem::path application_path)
|
||||||
|
{
|
||||||
|
std::println("Usage: {}", application_path.stem().string());
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
core::command_line_args_view command_line_args_view{argc, argv};
|
||||||
|
|
||||||
|
char help_option_name[]{"--help"};
|
||||||
|
char* fallback_argv[]{argv[0], help_option_name};
|
||||||
|
|
||||||
|
if (std::ranges::empty(command_line_args_view))
|
||||||
|
command_line_args_view = core::command_line_args_view(2, fallback_argv);
|
||||||
|
|
||||||
|
for (auto&& arg : command_line_args_view)
|
||||||
|
{
|
||||||
|
arg.with("--help", [&] {
|
||||||
|
print_help(command_line_args_view.appliation_path());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
project "cpp-application"
|
||||||
|
do
|
||||||
|
kind "ConsoleApp"
|
||||||
|
location "%{_MAIN_SCRIPT_DIR}/.build"
|
||||||
|
externalincludedirs {"%{_MAIN_SCRIPT_DIR}"}
|
||||||
|
files {
|
||||||
|
"**.cpp",
|
||||||
|
"**.h",
|
||||||
|
}
|
||||||
|
links {
|
||||||
|
"cpp-core-library",
|
||||||
|
}
|
||||||
|
end
|
||||||
@@ -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)};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
require("premake", ">=5.0.0-beta8")
|
||||||
|
|
||||||
|
workspace "cpp-template"
|
||||||
|
do
|
||||||
|
platforms {"x64"}
|
||||||
|
configurations {"Debug", "Release"}
|
||||||
|
startproject "cpp-application"
|
||||||
|
|
||||||
|
-- Default fields for all projects
|
||||||
|
targetdir "bin/%{cfg.buildcfg:lower()}"
|
||||||
|
objdir ".obj/%{cfg.buildcfg:lower()}"
|
||||||
|
cppdialect "C++23"
|
||||||
|
multiprocessorcompile "On"
|
||||||
|
optimize "Full"
|
||||||
|
symbols "On"
|
||||||
|
warnings "High"
|
||||||
|
|
||||||
|
filter "configurations:Debug"
|
||||||
|
do
|
||||||
|
optimize "Off"
|
||||||
|
symbols "Full"
|
||||||
|
end
|
||||||
|
|
||||||
|
filter ""
|
||||||
|
|
||||||
|
include "core-library"
|
||||||
|
include "application"
|
||||||
|
end
|
||||||
Reference in new issue
Block a user