├── .gitignore ├── cmake ├── brew-gcc-toolchain.cmake ├── astrConfig.cmake.in ├── default_libs.cmake ├── simpletargets.cmake ├── default_flags.cmake ├── setup_compiler.cmake ├── testing.cmake ├── default_warnings.cmake └── default_coverage.cmake ├── tests ├── CMakeLists.txt ├── test_main.cpp └── base │ ├── typename_test.cpp │ └── filename_test.cpp ├── run_clang_tidy.sh ├── README.md ├── include └── a4z │ ├── filename.hpp │ ├── typename.hpp │ └── astr.hpp ├── .github └── workflows │ └── cmake.yml ├── .clang-tidy ├── CMakePresets.json ├── CMakeLists.txt ├── .clang-format └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | -------------------------------------------------------------------------------- /cmake/brew-gcc-toolchain.cmake: -------------------------------------------------------------------------------- 1 | 2 | SET(CMAKE_C_COMPILER /opt/homebrew/bin/gcc-13) 3 | SET(CMAKE_CXX_COMPILER /opt/homebrew/bin/g++-13) 4 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_doctest(test-base 3 | SOURCES 4 | base/typename_test.cpp 5 | base/filename_test.cpp 6 | ) 7 | 8 | -------------------------------------------------------------------------------- /cmake/astrConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/astrTargets.cmake") 4 | 5 | check_required_components("astr") 6 | -------------------------------------------------------------------------------- /cmake/default_libs.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | find_package (Threads) 4 | 5 | add_library(_DefaultLibs INTERFACE) 6 | 7 | target_link_libraries(_DefaultLibs 8 | INTERFACE Threads::Threads 9 | ) 10 | 11 | add_library(default::libs ALIAS _DefaultLibs) 12 | -------------------------------------------------------------------------------- /run_clang_tidy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for file in $(git ls-files | grep -E '^(include|src)/.*\.(c|cpp|h|hpp)$') 4 | do 5 | echo 'Checking '$file 6 | clang-tidy -extra-arg=-Wno-unknown-warning-option --extra-arg=-std=c++$1 -p $2 --header-filter='^$' $file || exit 255 7 | done 8 | -------------------------------------------------------------------------------- /cmake/simpletargets.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | enable_testing() 4 | 5 | function(bin_from_file fname outname) 6 | get_filename_component(bname ${fname} NAME_WE) 7 | set(${outname} ${bname} PARENT_SCOPE) 8 | add_executable(${bname} ${fname}) 9 | target_link_libraries (${bname} 10 | PRIVATE default::flags 11 | ) 12 | endfunction(bin_from_file) 13 | 14 | 15 | -------------------------------------------------------------------------------- /cmake/default_flags.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | include(default_warnings) 4 | include(default_libs) 5 | include(default_coverage) 6 | 7 | add_library(_DefaultFlags INTERFACE) 8 | 9 | target_link_libraries(_DefaultFlags 10 | INTERFACE default::libs default::warnings default::coverage 11 | ) 12 | 13 | # TODO , this Windows part is of course totally untested 14 | # and it does not work if the dependencies are not adjusted accordently, 15 | # todo , if this is wanted, a custom tripplet is needed 16 | # target_compile_options(_DefaultFlags 17 | # INTERFACE 18 | # $<$,$>: /MTd> 19 | # $<$,$>: /MT> 20 | # ) 21 | add_library(default::flags ALIAS _DefaultFlags) 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # astr, compile-time array string 2 | 3 | An (opinionated) compile-time string processing library for C++20 and above. 4 | 5 | If wanted, the code can easily be adapted to C++17. 6 | Feel free to open an issue if you need help with that. 7 | 8 | **There are two use-cases demonstrating what this can be used for.** 9 | 10 | ## Getting short file names as compile time strings 11 | 12 | Reproducible and fix size 'strings' for the `__FILE__` name at compile time. 13 | 14 | The code is related to the blog post ['Compile time string literals processing, but why'](https://a4z.gitlab.io/blog/2023/11/04/Compiletime-string-literals-processing.html), which describes some more details about this feature. 15 | 16 | ## Getting type names as compile time strings 17 | 18 | There are many ways of faking reflections in C++ to get a typename, and there are several more or less famouse library solutions around this. 19 | 20 | The code here shows how that actually works, without being a fully fletched 'library'. 21 | 22 | There is also enough functionality to get the type name as a compile-time string and doing customizations that this can be used to solve some real world use cases. 23 | 24 | ## Documentation 25 | 26 | For now, please have a look at the files in [the testing directory](./tests/base). 27 | 28 | They should be easy to understand and show how to use the code. 29 | -------------------------------------------------------------------------------- /tests/test_main.cpp: -------------------------------------------------------------------------------- 1 | // #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 | // #include "doctest.h" 3 | 4 | #define DOCTEST_CONFIG_IMPLEMENT 5 | #include 6 | 7 | int main(int argc, char** argv) { 8 | // environment setup give me the code that should stand here 9 | 10 | doctest::Context context; // initialize 11 | 12 | // defaults 13 | // context.addFilter("test-case-exclude", "*math*"); // exclude test cases 14 | // with "math" in their name 15 | context.setOption("no-breaks", 16 | true); // don't break in the debugger when assertions fail 17 | 18 | context.applyCommandLine(argc, argv); 19 | 20 | // overrides 21 | context.setOption("abort-after", 22 | 5); // stop test execution after 5 failed assertions 23 | // context.setOption("sort", "name"); // sort the test cases by their name 24 | 25 | int res = context.run(); // run 26 | 27 | if (context.shouldExit()) // important - query flags (and --exit) rely on 28 | // the user doing this 29 | return res; // propagate the result of the tests 30 | 31 | int client_stuff_return_code = 0; 32 | // your program - if the testing framework is integrated in your production 33 | // code 34 | 35 | return res + client_stuff_return_code; // the result from doctest is 36 | // propagated here as well 37 | } 38 | -------------------------------------------------------------------------------- /cmake/setup_compiler.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | # enable ccache only if it is there 4 | find_program(CCACHE_BIN ccache) 5 | if(CCACHE_BIN) 6 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_BIN}) 7 | set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_BIN}) 8 | message("ccache binary foud, ccache enabled") 9 | endif() 10 | 11 | get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 12 | if(NOT isMultiConfig) 13 | message("No multiconfig project") 14 | if(NOT CMAKE_BUILD_TYPE) 15 | message("No build type, fix it for you") 16 | SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING 17 | "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." 18 | FORCE ) 19 | endif(NOT CMAKE_BUILD_TYPE) 20 | else(NOT isMultiConfig) 21 | message("** Multi config project") 22 | endif(NOT isMultiConfig) 23 | 24 | # Off, we do not want to annoy potential packager 25 | # option(WARN_ERROR "Thread warnings as errors. Default OFF" OFF) 26 | set(CMAKE_CXX_STANDARD 17) 27 | set(CXX_STANDARD_REQUIRED ON) 28 | set(CMAKE_CXX_EXTENSIONS OFF) 29 | SET(CMAKE_COMPILE_WARNING_AS_ERROR ON) # turn off with --compile-no-warning-as-error 30 | 31 | 32 | if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 33 | # https://stackoverflow.com/questions/77153800/xcode-15-c-compilation-errors 34 | # TODO ... 35 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-ld_classic") 36 | endif() 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /include/a4z/filename.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 a4z 2 | // 3 | // This Source Code Form is subject to the terms of the Mozilla Public 4 | // License, v. 2.0. If a copy of the MPL was not distributed with this 5 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 6 | 7 | #ifndef A4Z_FILENAME_HPP 8 | #define A4Z_FILENAME_HPP 9 | 10 | #include "astr.hpp" 11 | 12 | namespace a4z { 13 | 14 | constexpr char slash = on_windows() ? '\\' : '/'; 15 | 16 | #define a4z_file_name \ 17 | []() constexpr { \ 18 | constexpr const char* str = __FILE__; \ 19 | constexpr auto len = a4z::cstr_len(str); \ 20 | constexpr auto start{a4z::find_nth_r_occurrence(__FILE__, a4z::slash, 2)}; \ 21 | static_assert(start != a4z::npos); \ 22 | constexpr std::size_t astr_len = len - start; \ 23 | char data[astr_len] = {0}; \ 24 | for (std::size_t i = 0; i < astr_len; ++i) { \ 25 | data[i] = *(str + start + i + 1); \ 26 | } \ 27 | return a4z::astr{data}; \ 28 | } 29 | 30 | } // namespace a4z 31 | 32 | #endif // A4Z_FILENAME_HPP 33 | -------------------------------------------------------------------------------- /cmake/testing.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | option(FETCH_DOCTEST "Use fetch content to get doctest" ON) 4 | if (FETCH_DOCTEST) 5 | message(STATUS "Fetching doctest") 6 | 7 | include(FetchContent) 8 | 9 | FetchContent_Declare( 10 | doctest 11 | GIT_REPOSITORY https://github.com/onqtam/doctest 12 | GIT_TAG v2.4.11 13 | OVERRIDE_FIND_PACKAGE 14 | ) 15 | endif() 16 | 17 | set(DOCTEST_NO_INSTALL True) 18 | 19 | find_package(doctest CONFIG REQUIRED) 20 | 21 | add_library(doctest_main STATIC ${PROJECT_SOURCE_DIR}/tests/test_main.cpp) 22 | 23 | set(TEST_FRAMEWORK doctest::doctest) 24 | set(THIS_PROJECT_LIBS astr default::flags) 25 | 26 | target_link_libraries(doctest_main PUBLIC ${TEST_FRAMEWORK}) 27 | 28 | function (add_doctest NAME) 29 | 30 | set(option_args WILL_FAIL) 31 | set(value_args TIMEOUT) 32 | set(list_args SOURCES) 33 | 34 | cmake_parse_arguments(D_TEST 35 | "${option_args}" "${value_args}" "${list_args}" 36 | ${ARGN} 37 | ) 38 | 39 | add_executable(${NAME} ${D_TEST_SOURCES} $) 40 | target_link_libraries(${NAME} doctest_main ${TEST_FRAMEWORK} ${THIS_PROJECT_LIBS}) 41 | 42 | if(NOT D_TEST_TIMEOUT) 43 | set(D_TEST_TIMEOUT 3) 44 | endif() 45 | if(NOT D_TEST_WILL_FAIL) 46 | set(D_TEST_WILL_FAIL OFF) 47 | endif() 48 | 49 | add_test(NAME ${NAME} COMMAND ${NAME}) 50 | 51 | set_tests_properties(${NAME} 52 | PROPERTIES 53 | TIMEOUT ${D_TEST_TIMEOUT} 54 | WILL_FAIL ${D_TEST_WILL_FAIL} 55 | ) 56 | 57 | endfunction(add_doctest) 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake Build and Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | check-format: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | 18 | - name: Install dependencies 19 | run: | 20 | sudo apt-get update 21 | sudo apt-get install -y cmake ninja-build clang-format 22 | 23 | - name: Configure CMake 24 | run: cmake --preset ninja 25 | 26 | - name: Check format 27 | run: cmake --build --preset ninja --target clang-format-check 28 | 29 | build: 30 | runs-on: ${{ matrix.os }} 31 | strategy: 32 | matrix: 33 | os: [ubuntu-latest, windows-latest, macos-latest] 34 | include: 35 | - os: ubuntu-latest 36 | cmake_preset: ninja 37 | - os: windows-latest 38 | cmake_preset: msvc22 39 | - os: macos-latest 40 | cmake_preset: xcode 41 | 42 | steps: 43 | - name: Checkout code 44 | uses: actions/checkout@v4 45 | 46 | - name: Install dependencies on Ubuntu 47 | if: matrix.os == 'ubuntu-latest' 48 | run: | 49 | sudo apt-get update 50 | sudo apt-get install -y cmake ninja-build 51 | 52 | - name: Configure CMake 53 | run: | 54 | cmake --preset ${{ matrix.cmake_preset }} 55 | 56 | - name: Build 57 | run: | 58 | cmake --build --preset ${{ matrix.cmake_preset }} 59 | 60 | - name: Test 61 | run: | 62 | ctest --preset ${{ matrix.cmake_preset }} --output-on-failure 63 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: > 2 | *, 3 | -clang-analyzer-*, 4 | -google-*, 5 | -llvm-*, 6 | -llvmlibc-*, 7 | -altera-*, 8 | -fuchsia-*, 9 | -hicpp-no-array-decay, 10 | -hicpp-*, 11 | -performance-*, 12 | -readability-identifier-length, 13 | -readability-avoid-nested-conditional-operator, 14 | -bugprone-easily-swappable-parameters, 15 | -misc-no-recursion, 16 | -misc-non-private-member-variables-in-classes, 17 | cppcoreguidelines-*, 18 | -cppcoreguidelines-avoid-c-arrays, 19 | -cppcoreguidelines-pro-bounds-pointer-arithmetic, 20 | modernize-*, 21 | -modernize-use-trailing-return-type, 22 | -modernize-avoid-c-arrays, 23 | 24 | CheckOptions: 25 | - key: modernize-use-auto 26 | value: 'false' 27 | - key: cppcoreguidelines-avoid-magic-numbers 28 | value: 'false' 29 | - key: cppcoreguidelines-avoid-c-arrays 30 | value: 'true' 31 | - key: cppcoreguidelines-non-private-member-variables-in-classes 32 | value: 'true' 33 | - key: cppcoreguidelines-pro-type-member-init 34 | value: 'true' 35 | - key: cppcoreguidelines-pro-bounds-array-to-pointer-decay 36 | value: 'true' 37 | - key: cppcoreguidelines-pro-bounds-constant-array-index 38 | value: 'true' 39 | - key: modernize-avoid-bind 40 | value: 'true' 41 | - key: modernize-use-emplace 42 | value: 'true' 43 | - key: modernize-make-shared 44 | value: 'true' 45 | - key: modernize-make-unique 46 | value: 'true' 47 | - key: modernize-use-override 48 | value: 'true' 49 | - key: modernize-use-using 50 | value: 'true' 51 | - key: readability-identifier-naming.NamespaceCase 52 | value: lower_case 53 | - key: readability-identifier-naming.VariableName 54 | value: lower_case 55 | - key: readability-identifier-naming.FunctionCase 56 | value: lower_case 57 | 58 | WarningsAsErrors: '*' 59 | # HeaderFilterRegex: '' 60 | FormatStyle: 'file' 61 | -------------------------------------------------------------------------------- /cmake/default_warnings.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | 4 | add_library(_DefaultWarnings INTERFACE) 5 | target_compile_options(_DefaultWarnings 6 | INTERFACE 7 | $<$,$,$>: 8 | -Wall -Wextra -pedantic 9 | -Wdeprecated 10 | -Wformat-security 11 | -Wimplicit-fallthrough 12 | -Wmissing-braces 13 | -Wmissing-field-initializers 14 | -Wnon-virtual-dtor 15 | -Wnull-dereference 16 | -Wold-style-cast 17 | # -Wpadded # want that only for protocols where memcp on stucts in used 18 | -Wparentheses 19 | -Wpointer-arith 20 | -Wredundant-decls 21 | -Wreturn-type 22 | -Wsequence-point 23 | -Wshadow 24 | -Wswitch 25 | -Wuninitialized 26 | -Wunused-function 27 | -Wunused-variable 28 | -Wunused-variable 29 | -Wconversion 30 | -Wsign-conversion 31 | -Wsign-promo 32 | -Wfloat-conversion 33 | -pthread 34 | > 35 | 36 | $<$: -ferror-limit=3> 37 | 38 | $<$: -Wduplicated-branches 39 | -Wduplicated-cond 40 | -Wlogical-op 41 | -Wcast-align 42 | # -Wno-missing-field-initializers 43 | > 44 | 45 | $<$:/W4> 46 | ) 47 | 48 | # since cmake 3.24 we use COMPILE_WARNING_AS_ERROR 49 | # option(WARN_ERROR "Thread warnings as errors" OFF) 50 | 51 | # if(WARN_ERROR) 52 | # target_compile_options(_DefaultWarnings 53 | # INTERFACE 54 | # $<$,$,$>:-Werror> 55 | # $<$:/WX> 56 | # ) 57 | # endif(WARN_ERROR) 58 | 59 | add_library(default::warnings ALIAS _DefaultWarnings) 60 | -------------------------------------------------------------------------------- /cmake/default_coverage.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | option(COVERAGE "Enable coverage reporting" OFF) 4 | 5 | add_library(_DefaultCoverage INTERFACE) 6 | 7 | if (COVERAGE) 8 | 9 | message("Enable code coverage") 10 | 11 | target_compile_options(_DefaultCoverage 12 | INTERFACE 13 | $<$: --coverage> 14 | 15 | $<$: --coverage> 16 | ) 17 | 18 | target_link_options(_DefaultCoverage 19 | INTERFACE 20 | $<$: --coverage> 21 | 22 | $<$: --coverage> 23 | ) 24 | 25 | set(COVERAGE_BRANCHES "--rc branch_coverage=1") 26 | set(COVERAGE_WARNINGS "--ignore-errors gcov") 27 | set(GENHTML_WARNINGS "") 28 | if(APPLE) 29 | set(COVERAGE_WARNINGS "--ignore-errors gcov --ignore-errors inconsistent --ignore-errors unused --ignore-errors range --ignore-errors empty,empty") 30 | set(GENHTML_WARNINGS "--ignore-errors inconsistent") 31 | endif() 32 | separate_arguments(COVERAGE_BRANCHES) 33 | separate_arguments(COVERAGE_WARNINGS) 34 | separate_arguments(GENHTML_WARNINGS) 35 | add_custom_target(coverage 36 | COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/coverage 37 | COMMAND lcov --directory . --capture --output-file ${CMAKE_BINARY_DIR}/coverage/coverage.info ${COVERAGE_WARNINGS} ${COVERAGE_BRANCHES} 38 | COMMAND lcov --remove ${CMAKE_BINARY_DIR}/coverage/coverage.info '/usr/*' '*/tests/*' '*/_deps/*' '${CMAKE_SOURCE_DIR}/external/*' --output-file ${CMAKE_BINARY_DIR}/coverage/coverage.info.cleaned ${COVERAGE_WARNINGS} ${COVERAGE_BRANCHES} 39 | COMMAND genhtml --branch-coverage ${CMAKE_BINARY_DIR}/coverage/coverage.info.cleaned --output-directory ${CMAKE_BINARY_DIR}/coverage ${GENHTML_WARNINGS} ${COVERAGE_BRANCHES} 40 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 41 | ) 42 | endif(COVERAGE) 43 | 44 | add_library(default::coverage ALIAS _DefaultCoverage) 45 | -------------------------------------------------------------------------------- /include/a4z/typename.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 a4z 2 | // 3 | // This Source Code Form is subject to the terms of the Mozilla Public 4 | // License, v. 2.0. If a copy of the MPL was not distributed with this 5 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 6 | 7 | #ifndef A4Z_TYPENAME_HPP 8 | #define A4Z_TYPENAME_HPP 9 | 10 | #include 11 | #include "astr.hpp" 12 | 13 | namespace a4z { 14 | 15 | template 16 | constexpr const char* type_name_str() { 17 | #if defined(_MSC_VER) 18 | return __FUNCSIG__; 19 | #elif defined(__GNUC__) || defined(__clang__) 20 | return __PRETTY_FUNCTION__; 21 | #else 22 | error("compiler not supported, feel free to add a PR") 23 | #endif 24 | } 25 | 26 | template 27 | constexpr auto type_name() { 28 | #if defined(_MSC_VER) 29 | constexpr const char* thisname = __FUNCSIG__; 30 | constexpr auto ang = a4z::first_c_in('<', thisname); 31 | constexpr auto space = a4z::first_c_in(' ', ang); 32 | constexpr auto tstart = 33 | (space == nullptr) ? a4z::next_c(ang) : a4z::next_c(space); 34 | constexpr auto tend = a4z::last_c_in('>', thisname); 35 | 36 | // constexpr size_t len = tend - tstart; // very likely a distance 37 | 38 | #elif defined(__GNUC__) || defined(__clang__) 39 | constexpr const char* thisname = __PRETTY_FUNCTION__; 40 | constexpr auto eq = a4z::first_c_in('=', thisname); 41 | constexpr auto past_eq = a4z::next_c(eq); 42 | constexpr auto tstart = a4z::first_not(' ', past_eq); 43 | constexpr auto tend = a4z::last_c_in(']', thisname); 44 | 45 | #else 46 | error("compiler not supported, feel free to add a PR") 47 | #endif 48 | 49 | constexpr auto dist = tend - tstart; 50 | static_assert(dist > 0); 51 | constexpr size_t data_len = static_cast(dist) + 1; 52 | char data[data_len] = {0}; 53 | for (size_t i = 0; i < data_len - 1; ++i) { 54 | data[i] = *(tstart + i); 55 | } 56 | return a4z::astr{data}; 57 | } 58 | 59 | } // namespace a4z 60 | 61 | #endif // A4Z_TYPENAME_HPP 62 | -------------------------------------------------------------------------------- /tests/base/typename_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | // This shows a few use cases, 8 | // should be clear that this is not a real reflection and has limits 9 | 10 | SCENARIO("Check simple typename") { 11 | GIVEN("the typename of an int") { 12 | auto tn = a4z::type_name(); 13 | WHEN("expecting the according typename") { 14 | std::string expected = "int"; 15 | THEN("the typename matches the expected one") { 16 | CHECK(std::string{tn.c_str()} == expected); 17 | } 18 | } 19 | } 20 | } 21 | 22 | struct Foo {}; 23 | 24 | SCENARIO("Check struct typename") { 25 | GIVEN("the typename of Foo") { 26 | auto tn = a4z::type_name(); 27 | WHEN("expecting the according typename") { 28 | std::string expected = "Foo"; 29 | THEN("the typename matches the expected one") { 30 | CHECK(std::string{tn.c_str()} == expected); 31 | } 32 | } 33 | } 34 | } 35 | 36 | namespace bar { 37 | struct Foo {}; 38 | } // namespace bar 39 | 40 | SCENARIO("Check struct in a namespace typename") { 41 | GIVEN("the typename of Foo") { 42 | auto tn = a4z::type_name(); 43 | WHEN("expecting the according typename") { 44 | std::string expected = "bar::Foo"; 45 | THEN("the typename matches the expected one") { 46 | CHECK(std::string{tn.c_str()} == expected); 47 | } 48 | } 49 | } 50 | } 51 | 52 | // This shows how to customize the typename for a type where compilers have 53 | // different display names std::string could be something like 54 | // basic_string, allocator> and this is nothing 55 | // you want to see (except for debug purposes) 56 | namespace a4z { 57 | template <> 58 | constexpr auto type_name() { 59 | return a4z::astr<12>{"std::string"}; 60 | } 61 | } // namespace a4z 62 | 63 | // std::string is always a bit special , basic_string blab bla bla 64 | SCENARIO("Check specialized typename") { 65 | GIVEN("the typename of std::string") { 66 | constexpr auto tn = a4z::type_name(); 67 | static_assert(a4z::equal("std::string", tn.c_str())); // real compile time 68 | WHEN("expecting the according typename") { 69 | std::string expected = "std::string"; 70 | THEN("the typename matches the expected one") { 71 | CHECK(std::string{tn.c_str()} == expected); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 6, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 27, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "base", 11 | "hidden": true, 12 | "binaryDir": "${sourceDir}/build/${presetName}" 13 | }, 14 | { 15 | "inherits": "base", 16 | "name": "ninja", 17 | "displayName": "Default Config", 18 | "description": "Default build using Ninja", 19 | "generator": "Ninja Multi-Config" 20 | }, 21 | { 22 | "inherits": "base", 23 | "name": "brew-gcc", 24 | "displayName": "Brew Gcc", 25 | "description": "Gcc on Mac, Ninja Multiconfig", 26 | "generator": "Ninja Multi-Config", 27 | "toolchainFile": "cmake/brew-gcc-toolchain.cmake" 28 | }, 29 | { 30 | "inherits": "base", 31 | "name": "msvc22", 32 | "displayName": "VS 2022", 33 | "description": "Visual Studio 2022 Multiconfig", 34 | "generator": "Visual Studio 17 2022" 35 | }, 36 | { 37 | "inherits": "base", 38 | "name": "xcode", 39 | "displayName": "Xcode", 40 | "description": "Xcode Multiconfig", 41 | "generator": "Xcode" 42 | } 43 | ], 44 | "buildPresets": [ 45 | { 46 | "name": "ninja", 47 | "configurePreset": "ninja", 48 | "configuration": "Debug" 49 | }, 50 | { 51 | "name": "ninja-release", 52 | "configurePreset": "ninja", 53 | "configuration": "Release" 54 | }, 55 | { 56 | "name": "brew-gcc", 57 | "configurePreset": "brew-gcc", 58 | "configuration": "Debug" 59 | }, 60 | { 61 | "name": "brew-gcc-release", 62 | "configurePreset": "brew-gcc", 63 | "configuration": "Release" 64 | }, 65 | { 66 | "name": "msvc22", 67 | "configurePreset": "msvc22", 68 | "configuration": "Debug" 69 | }, 70 | { 71 | "name": "msvc22-release", 72 | "configurePreset": "msvc22", 73 | "configuration": "Release" 74 | }, 75 | { 76 | "name": "xcode", 77 | "configurePreset": "xcode", 78 | "configuration": "Debug" 79 | }, 80 | { 81 | "name": "xcode-release", 82 | "configurePreset": "xcode", 83 | "configuration": "Release" 84 | } 85 | 86 | ], 87 | "testPresets": [ 88 | { 89 | "name": "ninja", 90 | "configurePreset": "ninja", 91 | "configuration": "Debug" 92 | }, 93 | { 94 | "name": "ninja-release", 95 | "configurePreset": "ninja", 96 | "configuration": "Release" 97 | }, 98 | { 99 | "name": "brew-gcc", 100 | "configurePreset": "brew-gcc", 101 | "configuration": "Debug" 102 | }, 103 | { 104 | "name": "brew-gcc-release", 105 | "inherits": "brew-gcc", 106 | "configuration": "Release" 107 | }, 108 | { 109 | "name": "msvc22", 110 | "configurePreset": "msvc22", 111 | "configuration": "Debug" 112 | }, 113 | { 114 | "name": "msvc22-release", 115 | "inherits": "msvc22", 116 | "configuration": "Release" 117 | }, 118 | { 119 | "name": "xcode", 120 | "configurePreset": "xcode", 121 | "configuration": "Debug" 122 | }, 123 | { 124 | "name": "xcode-release", 125 | "inherits": "xcode", 126 | "configuration": "Release" 127 | } 128 | ] 129 | } 130 | -------------------------------------------------------------------------------- /tests/base/filename_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | SCENARIO("Check find slashes") { 8 | GIVEN("a string with more than 2 slashes") { 9 | constexpr char abc[] = "/a/b/c"; 10 | 11 | WHEN("looking for the second last string") { 12 | constexpr auto n = a4z::find_nth_r_occurrence(abc, '/', 2); 13 | THEN("we find it at the expected position") { 14 | CHECK(n == 2); 15 | CHECK(abc[n] == '/'); 16 | } 17 | } 18 | } 19 | 20 | GIVEN("a string with just 1 slash") { 21 | constexpr char abc[] = "ab/c"; 22 | 23 | WHEN("looking for the second last string") { 24 | constexpr auto n = a4z::find_nth_r_occurrence(abc, '/', 2); 25 | THEN("we get npos") { 26 | CHECK(n == std::string::npos); 27 | } 28 | } 29 | } 30 | // all I need now is copy the part into a carrier 31 | // and there is a constant file name implementation 32 | } 33 | 34 | SCENARIO("Truncate a astr") { 35 | GIVEN("some astr with 10 characters") { 36 | constexpr char abc[] = "0123456789"; 37 | constexpr a4z::astr a10(abc); 38 | REQUIRE(a10.size() == 10); 39 | WHEN("requesting the last 5 characters") { 40 | constexpr auto a5 = a10.last_n<5>(); 41 | THEN("we have a new astr of size 5") { 42 | CHECK(a5.size() == 5); 43 | std::string wanted = "56789"; 44 | std::string_view having = a5; 45 | CHECK(wanted == having); 46 | } 47 | } 48 | WHEN("requesting the last characters of the same size") { 49 | // defacto a copy 50 | constexpr auto other = a10.last_n(); 51 | THEN("we have a new astr of size 10") { 52 | CHECK(other.size() == a10.size()); 53 | std::string wanted = abc; 54 | std::string_view having = other; 55 | CHECK(wanted == having); 56 | } 57 | } 58 | WHEN("requesting the first 5 characters") { 59 | constexpr auto a5 = a10.first_n<5>(); 60 | THEN("we have a new astr of size 5") { 61 | CHECK(a5.size() == 5); 62 | std::string wanted = "01234"; 63 | std::string_view having = a5; 64 | CHECK(wanted == having); 65 | } 66 | } 67 | WHEN("requesting the first characters of the same size") { 68 | // defacto a copy 69 | constexpr auto other = a10.first_n(); 70 | THEN("we have a new astr of size 10") { 71 | CHECK(other.size() == a10.size()); 72 | std::string wanted = abc; 73 | std::string_view having = other; 74 | CHECK(wanted == having); 75 | } 76 | } 77 | } 78 | } 79 | 80 | SCENARIO("Test with filename macro") { 81 | GIVEN("the current filename") { 82 | constexpr auto fn = a4z_file_name(); 83 | 84 | WHEN("checking if it starts with base") { 85 | // cpp20 86 | // const auto starts_with_base = 87 | // std::string(fn.c_str()).starts_with("base"); 88 | const char* base = "base"; 89 | auto start_str = fn.first_n<4>(); 90 | const auto starts_with_base = a4z::equal(base, start_str.c_str()); 91 | THEN("we find it at the expected position") { 92 | CHECK(starts_with_base); 93 | } 94 | } 95 | AND_WHEN("checking if it ends with ") { 96 | const char* filename = "filename_test.cpp"; 97 | auto end_str = fn.last_n<17>(); 98 | const auto ends_with_filename = a4z::equal(filename, end_str.c_str()); 99 | // cpp20 100 | // std::string(fn.c_str()).ends_with("filename_test.cpp"); 101 | THEN("we find it at the expected position") { 102 | CHECK(ends_with_filename); 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.27) 3 | 4 | project(astr VERSION 0.3.0 LANGUAGES CXX) 5 | 6 | if(PROJECT_IS_TOP_LEVEL) 7 | # make git ignore the build directory 8 | file(WRITE ${CMAKE_BINARY_DIR}/.gitignore "*") 9 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 10 | list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") 11 | include(setup_compiler) 12 | include(default_flags) 13 | 14 | include(CTest) 15 | if (BUILD_TESTING) 16 | include(testing) 17 | add_subdirectory(tests) 18 | endif() 19 | 20 | option(ASTR_ADD_INSTALL "Add install target" ON) 21 | 22 | add_custom_target( 23 | clang-tidy 24 | COMMAND git ls-files | grep -E "^(include|src)/.*\.(c|cpp|h|hpp)$" | xargs clang-tidy --extra-arg=-std=c++${CMAKE_CXX_STANDARD} -p ${CMAKE_BINARY_DIR} --header-filter='^$' 25 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 26 | VERBATIM 27 | USES_TERMINAL 28 | ) 29 | 30 | add_custom_target( 31 | clang_tidy 32 | COMMAND ${CMAKE_SOURCE_DIR}/run_clang_tidy.sh ${CMAKE_CXX_STANDARD} ${CMAKE_BINARY_DIR} 33 | COMMENT "Running clang-tidy on each file individually" 34 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 35 | USES_TERMINAL 36 | ) 37 | 38 | if(WIN32) 39 | set(FORMAT_COMMAND powershell -Command "git ls-files | Where-Object {$_ -match '.*\\.(c|h|cpp|hpp)$'} | ForEach-Object {clang-format -i $_}") 40 | set(FORMAT_CHECK_COMMAND powershell -Command "git ls-files | Where-Object {$_ -match '.*\\.(c|h|cpp|hpp)$'} | ForEach-Object {clang-format --Werror --dry-run $_}") 41 | else() 42 | set(FORMAT_COMMAND git ls-files | grep -E ".*\\.(c|h|cpp|hpp)$" | xargs clang-format -i) 43 | set(FORMAT_CHECK_COMMAND git ls-files | grep -E ".*\\.(c|h|cpp|hpp)$" | xargs clang-format --Werror --dry-run) 44 | endif() 45 | 46 | add_custom_target( 47 | clang-format 48 | COMMAND ${FORMAT_COMMAND} 49 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 50 | VERBATIM 51 | ) 52 | 53 | add_custom_target( 54 | clang-format-check 55 | COMMAND ${FORMAT_CHECK_COMMAND} 56 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 57 | VERBATIM 58 | USES_TERMINAL 59 | ) 60 | 61 | else() 62 | option(ASTR_ADD_INSTALL "Add install target" OFF) 63 | endif() 64 | 65 | 66 | add_library(astr INTERFACE) 67 | 68 | target_sources(astr INTERFACE 69 | $ 70 | $ 71 | $ 72 | ) 73 | 74 | target_include_directories(astr INTERFACE 75 | $ 76 | $ 77 | ) 78 | add_library(a4z::astr ALIAS astr) 79 | 80 | 81 | 82 | if (ASTR_ADD_INSTALL) 83 | 84 | # include gnudirs and add installation of the header file of the astr library 85 | include(GNUInstallDirs) 86 | install(TARGETS astr EXPORT astrTargets) 87 | install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 88 | install(EXPORT astrTargets 89 | FILE astrTargets.cmake 90 | NAMESPACE a4z:: 91 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 92 | ) 93 | include(CMakePackageConfigHelpers) 94 | write_basic_package_version_file( 95 | ${CMAKE_CURRENT_BINARY_DIR}/astrConfigVersion.cmake 96 | COMPATIBILITY AnyNewerVersion 97 | ) 98 | configure_package_config_file( 99 | ${CMAKE_CURRENT_LIST_DIR}/cmake/astrConfig.cmake.in 100 | ${CMAKE_CURRENT_BINARY_DIR}/astrConfig.cmake 101 | INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 102 | ) 103 | install( 104 | FILES 105 | ${CMAKE_CURRENT_BINARY_DIR}/astrConfig.cmake 106 | ${CMAKE_CURRENT_BINARY_DIR}/astrConfigVersion.cmake 107 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 108 | ) 109 | 110 | endif() 111 | 112 | -------------------------------------------------------------------------------- /include/a4z/astr.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024 a4z 2 | // 3 | // This Source Code Form is subject to the terms of the Mozilla Public 4 | // License, v. 2.0. If a copy of the MPL was not distributed with this 5 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. 6 | 7 | #ifndef A4z_ASTR_HPP 8 | #define A4z_ASTR_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace a4z { 15 | 16 | template 17 | struct astr { 18 | char data[N] = {0}; 19 | 20 | constexpr astr() noexcept = default; 21 | 22 | constexpr explicit astr(const char (&arr)[N]) noexcept { 23 | for (std::size_t i = 0; i < N; ++i) { 24 | data[i] = *(arr + i); 25 | } 26 | } 27 | 28 | [[nodiscard]] constexpr const char* c_str() const noexcept { 29 | return &data[0]; 30 | } 31 | 32 | [[nodiscard]] constexpr std::size_t size() const noexcept { return N - 1; } 33 | 34 | char* begin() noexcept { return &data[0]; } 35 | char* end() noexcept { return &data[N - 1]; } 36 | 37 | [[nodiscard]] const char* begin() const noexcept { return &data[0]; } 38 | [[nodiscard]] const char* end() const noexcept { return &data[N - 1]; } 39 | 40 | [[nodiscard]] const char* cbegin() const noexcept { return &data[0]; } 41 | [[nodiscard]] const char* cend() const noexcept { return &data[N - 1]; } 42 | 43 | constexpr operator std::string_view() const noexcept { 44 | return std::string_view(data, size()); 45 | } 46 | 47 | template 48 | constexpr auto last_n() const noexcept -> astr { 49 | static_assert(N > T, 50 | "Wanted sized T cannot be greater than actual size N"); 51 | astr result; 52 | constexpr std::size_t start = N - T - 1; // N > T is asserted above 53 | // cpp20, not yet 54 | // std::copy(data + start, data + N, result.data); 55 | for (size_t i = start; i < N; ++i) { 56 | result.data[i - start] = data[i]; 57 | } 58 | return result; 59 | } 60 | 61 | template 62 | constexpr auto first_n() const noexcept -> astr { 63 | static_assert(N > T, 64 | "Wanted sized T cannot be greater than actual size N"); 65 | astr result; 66 | constexpr std::size_t last = T; 67 | // cpp20, not yet 68 | // std::copy(data, data + last, result.data); 69 | for (size_t i = 0; i < last; ++i) { 70 | result.data[i] = data[i]; 71 | } 72 | return result; 73 | } 74 | }; 75 | 76 | constexpr bool equal(char const* a, char const* b) { 77 | return *a == *b && (*a == '\0' || equal(a + 1, b + 1)); 78 | } 79 | 80 | constexpr const char* next_c(const char* str) { 81 | return *(str + 1) == '\0' ? nullptr : str + 1; 82 | } 83 | 84 | template 85 | constexpr const char* first_char(const char* str, int idx) { 86 | return *(str + idx) == c ? str + idx 87 | : *(str + idx) == '\0' ? nullptr 88 | : first_char(str, idx + 1); 89 | } 90 | 91 | template 92 | constexpr const char* first_char_in(const char (&str)[N]) { 93 | return first_char(str, 0); 94 | } 95 | 96 | constexpr const char* first_not(char c, const char* str, int idx = 0) { 97 | return *(str + idx) != c ? str + idx 98 | : *(str + idx) == '\0' ? nullptr 99 | : first_not(c, str, idx + 1); 100 | } 101 | 102 | constexpr const char* first_c(char c, const char* str, int idx) { 103 | return *(str + idx) == c ? str + idx 104 | : *(str + idx) == '\0' ? nullptr 105 | : first_c(c, str, idx + 1); 106 | } 107 | 108 | constexpr const char* first_c_in(char c, const char* str) { 109 | return first_c(c, str, 0); 110 | } 111 | 112 | constexpr const char* last_c_in(char c, const char* str) { 113 | const auto* f = first_c_in(c, str); 114 | const auto* n = f; 115 | while (n != nullptr) { 116 | f = n++; 117 | n = first_c_in(c, n); 118 | } 119 | 120 | return f; 121 | } 122 | 123 | constexpr const char* last_char(char c, const char* str, int idx) { 124 | return *(str + idx) == c ? str + idx 125 | : idx == 0 ? nullptr 126 | : last_char(c, str, idx - 1); 127 | } 128 | 129 | template 130 | constexpr const char* last_char_in(char c, const char (&str)[N]) { 131 | return last_char(c, str, N - 1); 132 | } 133 | 134 | constexpr std::size_t cstr_len(const char* str) { 135 | std::size_t len = 0; 136 | while (*(str + len) != '\0') { 137 | ++len; 138 | } 139 | return len; 140 | } 141 | 142 | constexpr auto npos = std::numeric_limits::max(); 143 | 144 | template 145 | constexpr std::size_t find_nth_r_occurrence(const char (&str)[N], 146 | char ch, 147 | std::size_t n) { 148 | std::size_t count = 0; 149 | for (std::size_t i = N; i-- > 0;) { 150 | if (str[i] == ch) { 151 | ++count; 152 | if (count == n) { 153 | return i; 154 | } 155 | } 156 | } 157 | return npos; // Not found 158 | } 159 | 160 | constexpr bool on_windows() { 161 | #ifdef _WIN32 162 | return true; 163 | #else 164 | return false; 165 | #endif 166 | } 167 | 168 | } // namespace a4z 169 | 170 | #endif // A4z_ASTR_HPP 171 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Chromium 4 | AccessModifierOffset: -1 5 | AlignAfterOpenBracket: Align 6 | AlignArrayOfStructures: None 7 | AlignConsecutiveMacros: None 8 | AlignConsecutiveAssignments: None 9 | AlignConsecutiveBitFields: None 10 | AlignConsecutiveDeclarations: None 11 | AlignEscapedNewlines: Left 12 | AlignOperands: Align 13 | AlignTrailingComments: true 14 | AllowAllArgumentsOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: false 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Never 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: Inline 20 | AllowShortLambdasOnASingleLine: All 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: true 26 | AlwaysBreakTemplateDeclarations: Yes 27 | AttributeMacros: 28 | - __capability 29 | BinPackArguments: true 30 | BinPackParameters: false 31 | BraceWrapping: 32 | AfterCaseLabel: false 33 | AfterClass: false 34 | AfterControlStatement: Never 35 | AfterEnum: false 36 | AfterFunction: false 37 | AfterNamespace: false 38 | AfterObjCDeclaration: false 39 | AfterStruct: false 40 | AfterUnion: false 41 | AfterExternBlock: false 42 | BeforeCatch: false 43 | BeforeElse: false 44 | BeforeLambdaBody: false 45 | BeforeWhile: false 46 | IndentBraces: false 47 | SplitEmptyFunction: true 48 | SplitEmptyRecord: true 49 | SplitEmptyNamespace: true 50 | BreakBeforeBinaryOperators: None 51 | BreakBeforeConceptDeclarations: true 52 | BreakBeforeBraces: Attach 53 | BreakBeforeInheritanceComma: false 54 | BreakInheritanceList: BeforeColon 55 | BreakBeforeTernaryOperators: true 56 | BreakConstructorInitializersBeforeComma: false 57 | BreakConstructorInitializers: BeforeColon 58 | BreakAfterJavaFieldAnnotations: false 59 | BreakStringLiterals: true 60 | ColumnLimit: 80 61 | CommentPragmas: '^ IWYU pragma:' 62 | QualifierAlignment: Leave 63 | CompactNamespaces: false 64 | ConstructorInitializerIndentWidth: 4 65 | ContinuationIndentWidth: 4 66 | Cpp11BracedListStyle: true 67 | DeriveLineEnding: true 68 | DerivePointerAlignment: false 69 | DisableFormat: false 70 | EmptyLineAfterAccessModifier: Never 71 | EmptyLineBeforeAccessModifier: LogicalBlock 72 | ExperimentalAutoDetectBinPacking: false 73 | PackConstructorInitializers: NextLine 74 | BasedOnStyle: '' 75 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 76 | AllowAllConstructorInitializersOnNextLine: true 77 | FixNamespaceComments: true 78 | ForEachMacros: 79 | - foreach 80 | - Q_FOREACH 81 | - BOOST_FOREACH 82 | IfMacros: 83 | - KJ_IF_MAYBE 84 | IncludeBlocks: Preserve 85 | IncludeCategories: 86 | - Regex: '^' 87 | Priority: 2 88 | SortPriority: 0 89 | CaseSensitive: false 90 | - Regex: '^<.*\.h>' 91 | Priority: 1 92 | SortPriority: 0 93 | CaseSensitive: false 94 | - Regex: '^<.*' 95 | Priority: 2 96 | SortPriority: 0 97 | CaseSensitive: false 98 | - Regex: '.*' 99 | Priority: 3 100 | SortPriority: 0 101 | CaseSensitive: false 102 | IncludeIsMainRegex: '([-_](test|unittest))?$' 103 | IncludeIsMainSourceRegex: '' 104 | IndentAccessModifiers: false 105 | IndentCaseLabels: true 106 | IndentCaseBlocks: false 107 | IndentGotoLabels: true 108 | IndentPPDirectives: None 109 | IndentExternBlock: AfterExternBlock 110 | IndentRequires: false 111 | IndentWidth: 2 112 | IndentWrappedFunctionNames: false 113 | InsertTrailingCommas: None 114 | JavaScriptQuotes: Leave 115 | JavaScriptWrapImports: true 116 | KeepEmptyLinesAtTheStartOfBlocks: false 117 | LambdaBodyIndentation: Signature 118 | MacroBlockBegin: '' 119 | MacroBlockEnd: '' 120 | MaxEmptyLinesToKeep: 1 121 | NamespaceIndentation: All 122 | ObjCBinPackProtocolList: Never 123 | ObjCBlockIndentWidth: 2 124 | ObjCBreakBeforeNestedBlockParam: true 125 | ObjCSpaceAfterProperty: false 126 | ObjCSpaceBeforeProtocolList: true 127 | PenaltyBreakAssignment: 2 128 | PenaltyBreakBeforeFirstCallParameter: 1 129 | PenaltyBreakComment: 300 130 | PenaltyBreakFirstLessLess: 120 131 | PenaltyBreakOpenParenthesis: 0 132 | PenaltyBreakString: 1000 133 | PenaltyBreakTemplateDeclaration: 10 134 | PenaltyExcessCharacter: 1000000 135 | PenaltyReturnTypeOnItsOwnLine: 200 136 | PenaltyIndentedWhitespace: 0 137 | PointerAlignment: Left 138 | PPIndentWidth: -1 139 | RawStringFormats: 140 | - Language: Cpp 141 | Delimiters: 142 | - cc 143 | - CC 144 | - cpp 145 | - Cpp 146 | - CPP 147 | - 'c++' 148 | - 'C++' 149 | CanonicalDelimiter: '' 150 | BasedOnStyle: google 151 | - Language: TextProto 152 | Delimiters: 153 | - pb 154 | - PB 155 | - proto 156 | - PROTO 157 | EnclosingFunctions: 158 | - EqualsProto 159 | - EquivToProto 160 | - PARSE_PARTIAL_TEXT_PROTO 161 | - PARSE_TEST_PROTO 162 | - PARSE_TEXT_PROTO 163 | - ParseTextOrDie 164 | - ParseTextProtoOrDie 165 | - ParseTestProto 166 | - ParsePartialTestProto 167 | CanonicalDelimiter: pb 168 | BasedOnStyle: google 169 | ReferenceAlignment: Pointer 170 | ReflowComments: true 171 | RemoveBracesLLVM: false 172 | SeparateDefinitionBlocks: Leave 173 | ShortNamespaceLines: 1 174 | SortIncludes: CaseSensitive 175 | SortJavaStaticImport: Before 176 | SortUsingDeclarations: true 177 | SpaceAfterCStyleCast: false 178 | SpaceAfterLogicalNot: false 179 | SpaceAfterTemplateKeyword: true 180 | SpaceBeforeAssignmentOperators: true 181 | SpaceBeforeCaseColon: false 182 | SpaceBeforeCpp11BracedList: false 183 | SpaceBeforeCtorInitializerColon: true 184 | SpaceBeforeInheritanceColon: true 185 | SpaceBeforeParens: ControlStatements 186 | SpaceBeforeParensOptions: 187 | AfterControlStatements: true 188 | AfterForeachMacros: true 189 | AfterFunctionDefinitionName: false 190 | AfterFunctionDeclarationName: false 191 | AfterIfMacros: true 192 | AfterOverloadedOperator: false 193 | BeforeNonEmptyParentheses: false 194 | SpaceAroundPointerQualifiers: Default 195 | SpaceBeforeRangeBasedForLoopColon: true 196 | SpaceInEmptyBlock: false 197 | SpaceInEmptyParentheses: false 198 | SpacesBeforeTrailingComments: 2 199 | SpacesInAngles: Never 200 | SpacesInConditionalStatement: false 201 | SpacesInContainerLiterals: true 202 | SpacesInCStyleCastParentheses: false 203 | SpacesInLineCommentPrefix: 204 | Minimum: 1 205 | Maximum: -1 206 | SpacesInParentheses: false 207 | SpacesInSquareBrackets: false 208 | SpaceBeforeSquareBrackets: false 209 | BitFieldColonSpacing: Both 210 | Standard: Auto 211 | StatementAttributeLikeMacros: 212 | - Q_EMIT 213 | StatementMacros: 214 | - Q_UNUSED 215 | - QT_REQUIRE_VERSION 216 | TabWidth: 8 217 | UseCRLF: false 218 | UseTab: Never 219 | WhitespaceSensitiveMacros: 220 | - STRINGIZE 221 | - PP_STRINGIZE 222 | - BOOST_PP_STRINGIZE 223 | - NS_SWIFT_NAME 224 | - CF_SWIFT_NAME 225 | ... 226 | 227 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at https://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. --------------------------------------------------------------------------------