├── .gitignore ├── single-header ├── shorty.hpp.in ├── CMakeLists.txt ├── generate.cmake └── shorty.hpp ├── source ├── shorty │ ├── ops.cppm │ ├── compatibility │ │ ├── concepts.cppm │ │ ├── pack-indexing.cppm │ │ ├── concepts.hpp │ │ └── pack-indexing.hpp │ ├── literals.cppm │ ├── shorty.cppm │ ├── leaves.cppm │ ├── shorty.hpp │ ├── literals.hpp │ ├── ops.hpp │ └── leaves.hpp └── CMakeLists.txt ├── examples ├── CMakeLists.txt ├── test-single-header.cpp └── test.cpp ├── .tm_properties ├── cmake ├── colors.cmake ├── pedantic.cmake └── coverage.cmake ├── CMakeLists.txt ├── README.md ├── .clang-format ├── LICENSE └── shorty.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build* -------------------------------------------------------------------------------- /single-header/shorty.hpp.in: -------------------------------------------------------------------------------- 1 | #ifndef SHORTY_HPP 2 | #define SHORTY_HPP 3 | 4 | @CONTENT_OF_SINGLE_HEADER@ 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /source/shorty/ops.cppm: -------------------------------------------------------------------------------- 1 | export module shorty:ops; 2 | 3 | import std; 4 | import :concepts; 5 | 6 | #ifndef SHORTY_IS_IN_MODULE 7 | #define SHORTY_IS_IN_MODULE 8 | #endif 9 | 10 | #include "ops.hpp" 11 | -------------------------------------------------------------------------------- /source/shorty/compatibility/concepts.cppm: -------------------------------------------------------------------------------- 1 | export module shorty:concepts; 2 | 3 | import std; 4 | 5 | #ifndef SHORTY_IS_IN_MODULE 6 | #define SHORTY_IS_IN_MODULE 7 | #endif 8 | 9 | #include "concepts.hpp" 10 | -------------------------------------------------------------------------------- /source/shorty/literals.cppm: -------------------------------------------------------------------------------- 1 | export module shorty:literals; 2 | 3 | import std; 4 | import :leaves; 5 | 6 | #ifndef SHORTY_IS_IN_MODULE 7 | #define SHORTY_IS_IN_MODULE 8 | #endif 9 | 10 | #include "literals.hpp" 11 | -------------------------------------------------------------------------------- /source/shorty/compatibility/pack-indexing.cppm: -------------------------------------------------------------------------------- 1 | export module shorty:pack_indexing; 2 | 3 | import std; 4 | 5 | #ifndef SHORTY_IS_IN_MODULE 6 | #define SHORTY_IS_IN_MODULE 7 | #endif 8 | 9 | #include "pack-indexing.hpp" 10 | -------------------------------------------------------------------------------- /source/shorty/shorty.cppm: -------------------------------------------------------------------------------- 1 | export module shorty; 2 | 3 | import std; 4 | export import :literals; 5 | export import :concepts; 6 | 7 | #ifndef SHORTY_IS_IN_MODULE 8 | #define SHORTY_IS_IN_MODULE 9 | #endif 10 | 11 | #include "shorty.hpp" 12 | -------------------------------------------------------------------------------- /source/shorty/leaves.cppm: -------------------------------------------------------------------------------- 1 | export module shorty:leaves; 2 | 3 | import std; 4 | import :pack_indexing; 5 | import :concepts; 6 | import :ops; 7 | 8 | #ifndef SHORTY_IS_IN_MODULE 9 | #define SHORTY_IS_IN_MODULE 10 | #endif 11 | 12 | #include "leaves.hpp" 13 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test test.cpp) 2 | target_link_libraries(test PRIVATE shorty) 3 | 4 | add_executable(test-single-header test-single-header.cpp) 5 | target_link_libraries(test-single-header PRIVATE shorty-single-header) 6 | 7 | add_custom_target(examples DEPENDS test test-single-header) 8 | -------------------------------------------------------------------------------- /source/shorty/shorty.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHORTY_SHORTY_HPP 2 | #define SHORTY_SHORTY_HPP 3 | 4 | #ifdef SHORTY_IS_IN_MODULE 5 | #define SHORTY_EXPORT export 6 | #else // SHORTY_IS_IN_MODULE 7 | #include "literals.hpp" 8 | #define SHORTY_EXPORT 9 | #endif // SHORTY_IS_IN_MODULE 10 | 11 | SHORTY_EXPORT template struct identify; 12 | 13 | namespace shorty { 14 | 15 | } 16 | 17 | #endif // SHORTY_SHORTY_HPP 18 | -------------------------------------------------------------------------------- /.tm_properties: -------------------------------------------------------------------------------- 1 | CLANG_FORMAT_ON_SAVE = true 2 | 3 | excludeDirectories = "{$excludeDirectories,build}" 4 | includeDirectories = "{$includeDirectories}" 5 | include = "{$include,.gitignore,.gitattributes,.clang-format,.github}" 6 | excludeInFolderSearch = "{$excludeInFolderSearch,build,external,*-single-header.hpp}" 7 | includeInFolderSearch = "{$includeInFolderSearch}" 8 | excludeInFileChooser = "{$excludeInFileChooser}" 9 | softTabs = false 10 | tabSize = 2 11 | -------------------------------------------------------------------------------- /cmake/colors.cmake: -------------------------------------------------------------------------------- 1 | option (FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." ON) 2 | if (${FORCE_COLORED_OUTPUT}) 3 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 4 | add_compile_options ($<$:-fdiagnostics-color=always>) 5 | add_compile_options ($<$:-fdiagnostics-color=always>) 6 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 7 | add_compile_options ($<$:-fcolor-diagnostics>) 8 | add_compile_options ($<$:-fcolor-diagnostics>) 9 | endif () 10 | endif () -------------------------------------------------------------------------------- /examples/test-single-header.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | using namespace shorty::literals; 8 | 9 | auto data = std::array{1, 2, 3, 4, 5}; 10 | auto indices = std::array{0, 0, 4, 4, 1}; 11 | 12 | std::ranges::sort(indices, $lhs < $rhs); 13 | 14 | for (auto v: indices | std::views::transform($(data)[$($0)])) { 15 | std::println("{}", v); 16 | } 17 | 18 | std::println("zip:"); 19 | auto a = std::array{1, 2, 3, 4, 5}; 20 | auto b = std::array{2, 0, 1, 1, 3}; 21 | for (auto v: std::views::zip(a, b) | std::views::transform($0 + $1)) { 22 | std::println("{}", v); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 4.0) 2 | 3 | list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 4 | 5 | option(SHORTY_IS_IN_MODULE "build shorty library as a c++ module" ON) 6 | 7 | if (SHORTY_IS_IN_MODULE) 8 | set(CMAKE_CXX_STANDARD 23) 9 | set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "a9e1cf81-9932-4810-974b-6eccaf14e457") 10 | set(CMAKE_COLOR_DIAGNOSTICS ON) 11 | 12 | set(CMAKE_CXX_STANDARD_REQUIRED OFF) 13 | set(CMAKE_CXX_MODULE_STD 1) 14 | endif() 15 | 16 | include(colors) 17 | include(pedantic) 18 | 19 | project(shorty VERSION 1.0 LANGUAGES CXX) 20 | 21 | add_subdirectory(source) 22 | add_subdirectory(single-header EXCLUDE_FROM_ALL) 23 | add_subdirectory(examples EXCLUDE_FROM_ALL) 24 | 25 | 26 | -------------------------------------------------------------------------------- /single-header/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_custom_target(single-header DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/shorty.hpp) 2 | 3 | message(STATUS "${SHORTY_HEADERS}") 4 | 5 | add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/shorty.hpp COMMAND ${CMAKE_COMMAND} -DINPUT=${CMAKE_SOURCE_DIR}/source/shorty/shorty.hpp 6 | -DTEMPORARY=${CMAKE_CURRENT_BINARY_DIR}/tmp.hpp 7 | -DTEMPLATE=${CMAKE_CURRENT_SOURCE_DIR}/shorty.hpp.in 8 | -DOUTPUT=${CMAKE_CURRENT_SOURCE_DIR}/shorty.hpp 9 | -DINCLUDE_DIRECTORY=${CMAKE_SOURCE_DIR}/source/shorty 10 | -P ${CMAKE_CURRENT_SOURCE_DIR}/generate.cmake 11 | DEPENDS 12 | ${CMAKE_CURRENT_SOURCE_DIR}/generate.cmake 13 | ${SHORTY_HEADERS} 14 | ) 15 | 16 | add_library(shorty-single-header INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/shorty.hpp) 17 | add_dependencies(shorty-single-header single-header) 18 | target_compile_features(shorty-single-header INTERFACE cxx_std_26) 19 | target_include_directories(shorty-single-header INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -------------------------------------------------------------------------------- /single-header/generate.cmake: -------------------------------------------------------------------------------- 1 | message(STATUS "Generating shorty.hpp") 2 | 3 | # use QUOM to create basic single header 4 | set(COMMAND python3 -m quom ${INPUT} tmp.hpp --include_guard "SHORTY_SHORTY_.*" --include_directory ${INCLUDE_DIRECTORY} --trim) 5 | 6 | execute_process(COMMAND ${COMMAND} ERROR_VARIABLE ERRORS OUTPUT_VARIABLE OUTPUTS RESULT_VARIABLE RESULT_VAR) 7 | 8 | file (READ tmp.hpp CONTENT_TMP) 9 | 10 | string(REGEX REPLACE "[^\n]*SHORTY_IS_IN_MODULE" "" CONTENT_TMP2 "${CONTENT_TMP}") 11 | string(REGEX REPLACE "#define SHORTY_EXPORT[^\n]*\n" "" CONTENT_TMP3 "${CONTENT_TMP2}") 12 | string(REGEX REPLACE "SHORTY_EXPORT *" "" CONTENT_TMP4 "${CONTENT_TMP3}") 13 | 14 | #message(STATUS "${CONTENT_TMP4}") 15 | 16 | set(CONTENT_OF_SINGLE_HEADER "${CONTENT_TMP4}") 17 | 18 | configure_file(${TEMPLATE} ${OUTPUT} @ONLY) 19 | 20 | execute_process(COMMAND clang-format -i ${OUTPUT} RESULT_VARIABLE RESULT_VAR) 21 | 22 | #message(STATUS "clang-format = ${RESULT_VAR}") 23 | 24 | -------------------------------------------------------------------------------- /source/shorty/compatibility/concepts.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHORTY_SHORTY_COMPATIBILITY_CONCEPTS_HPP 2 | #define SHORTY_SHORTY_COMPATIBILITY_CONCEPTS_HPP 3 | 4 | #ifdef SHORTY_IS_IN_MODULE 5 | #define SHORTY_EXPORT export 6 | #else // SHORTY_IS_IN_MODULE 7 | #include 8 | #include 9 | #include 10 | #include 11 | #endif // SHORTY_IS_IN_MODULE 12 | 13 | namespace shorty { 14 | 15 | template constexpr bool is_tuple_like = false; 16 | template constexpr bool is_tuple_like> = true; 17 | template constexpr bool is_tuple_like> = true; 18 | template constexpr bool is_tuple_like> = true; 19 | template constexpr bool is_tuple_like> = true; 20 | // TODO subrange 21 | 22 | SHORTY_EXPORT template concept tuple_like = is_tuple_like>; 23 | 24 | } // namespace shorty 25 | 26 | #endif // SHORTY_SHORTY_COMPATIBILITY_CONCEPTS_HPP 27 | -------------------------------------------------------------------------------- /source/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SHORTY_SOURCES shorty.cppm literals.cppm leaves.cppm ops.cppm compatibility/pack-indexing.cppm compatibility/concepts.cppm) 2 | 3 | set(SHORTY_HEADERS ${SHORTY_SOURCES}) 4 | list(TRANSFORM SHORTY_HEADERS REPLACE "(.*)\.cppm$" "\\1.hpp") 5 | 6 | list(TRANSFORM SHORTY_HEADERS PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/shorty/") 7 | list(TRANSFORM SHORTY_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/shorty/") 8 | 9 | 10 | if(SHORTY_IS_IN_MODULE) 11 | add_library(shorty) 12 | target_sources(shorty PUBLIC FILE_SET modules TYPE CXX_MODULES FILES ${SHORTY_SOURCES}) 13 | target_compile_features(shorty PUBLIC cxx_std_26) 14 | target_include_directories(shorty PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) 15 | #set_target_properties(shorty PROPERTIES CXX_MODULE_STD ON) 16 | target_compile_definitions(shorty PUBLIC SHORTY_IS_IN_MODULE) 17 | else() 18 | add_library(shorty INTERFACE) 19 | target_sources(shorty INTERFACE FILE_SET headers TYPE HEADERS FILES ${SHORTY_HEADERS}) 20 | target_compile_features(shorty INTERFACE cxx_std_26) 21 | target_include_directories(shorty INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 22 | endif() 23 | 24 | set(SHORTY_HEADERS ${SHORTY_HEADERS} PARENT_SCOPE) -------------------------------------------------------------------------------- /source/shorty/compatibility/pack-indexing.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHORTY_SHORTY_COMPATIBILITY_PACK_INDEXING_HPP 2 | #define SHORTY_SHORTY_COMPATIBILITY_PACK_INDEXING_HPP 3 | 4 | #ifdef SHORTY_IS_IN_MODULE 5 | #define SHORTY_EXPORT export 6 | #else // SHORTY_IS_IN_MODULE 7 | #include 8 | #endif // SHORTY_IS_IN_MODULE 9 | 10 | namespace shorty { 11 | 12 | #if __cpp_pack_indexing >= 202311L 13 | template using first = Ts...[0]; 14 | template constexpr auto first_thing(Ts &&... args) { 15 | return args...[0]; 16 | } 17 | 18 | #else 19 | 20 | template struct head_helper; 21 | template struct head_helper { 22 | using result = Head; 23 | }; 24 | template constexpr auto first_thing(Head && head, Ts &&...) { 25 | return head; 26 | } 27 | 28 | template using first = head_helper::result; 29 | 30 | template constexpr auto extract_nth(First && first, Args &&... args) noexcept { 31 | if constexpr (N == 0u) { 32 | return first; 33 | } else { 34 | return extract_nth(std::forward(args)...); 35 | } 36 | } 37 | 38 | #endif 39 | 40 | } // namespace shorty 41 | 42 | #endif // SHORTY_SHORTY_COMPATIBILITY_PACK_INDEXING_HPP 43 | -------------------------------------------------------------------------------- /cmake/pedantic.cmake: -------------------------------------------------------------------------------- 1 | macro(add_c_and_cxx_compile_options NAME) 2 | add_compile_options("$<$:${NAME}>") 3 | add_compile_options("$<$:${NAME}>") 4 | endmacro() 5 | 6 | macro(add_c_and_cxx_compile_definitions NAME) 7 | add_compile_definitions("$<$:${NAME}>") 8 | add_compile_definitions("$<$:${NAME}>") 9 | endmacro() 10 | 11 | if (MSVC) 12 | add_c_and_cxx_compile_options("/W4") 13 | add_c_and_cxx_compile_options("/WX") 14 | else() 15 | add_c_and_cxx_compile_options("-Wall") 16 | add_c_and_cxx_compile_options("-Wextra") 17 | add_c_and_cxx_compile_options("-pedantic") 18 | add_c_and_cxx_compile_options("-Wshadow") 19 | add_c_and_cxx_compile_options("-Wconversion") 20 | add_c_and_cxx_compile_options("-Werror") 21 | add_c_and_cxx_compile_options("-Wno-dollar-in-identifier-extension") 22 | 23 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 24 | add_c_and_cxx_compile_definitions("_LIBCPP_ENABLE_NODISCARD") 25 | 26 | if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) 27 | add_c_and_cxx_compile_options("-Wno-missing-braces") 28 | endif() 29 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") 30 | add_c_and_cxx_compile_definitions("_LIBCPP_ENABLE_NODISCARD") 31 | add_c_and_cxx_compile_options("-Wno-missing-braces") 32 | endif() 33 | endif() 34 | -------------------------------------------------------------------------------- /examples/test.cpp: -------------------------------------------------------------------------------- 1 | #ifdef SHORTY_IS_IN_MODULE 2 | import shorty; 3 | import std; 4 | #else 5 | #include 6 | #include 7 | #include 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | int main() { 14 | using namespace shorty::literals; 15 | 16 | auto data = std::array{1, 2, 3, 4, 5}; 17 | std::ranges::sort(data, $lhs < $rhs); 18 | 19 | auto indices = std::array{0, 0, 4, 4, 1}; 20 | for (auto v: indices | std::views::transform($(data)[$0])) { 21 | std::println("{}", v); 22 | } 23 | 24 | std::println("zip:"); 25 | auto a = std::array{1, 2, 3, 4, 5}; 26 | auto b = std::array{2, 0, 1, 1, 3}; 27 | auto c = std::array{1, 1, 1, 0, 1}; 28 | for (auto v: std::views::zip(a, b, c) | std::views::transform(($a + $b) * $c)) { 29 | std::println("{}", v); 30 | } 31 | 32 | std::println("squares:"); 33 | constexpr auto sqrt = [](std::floating_point auto v) { 34 | return std::sqrt(v); 35 | }; 36 | 37 | auto values = std::array{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; 38 | for (auto v: values | std::views::transform($($0))) { 39 | std::println("{}", v); 40 | } 41 | 42 | [[maybe_unused]] auto cast_to_int = $($0); 43 | assert(cast_to_int(42.3) == 42); 44 | 45 | // auto wrong_expr = $x + $a; 46 | auto expr = $0 + $1; 47 | assert(expr(1, 4) == 5); 48 | 49 | auto make_tuple = ($0, $1, $2); 50 | std::tuple r = make_tuple(1, 2, 3); 51 | auto [t0, t1, t2] = r; 52 | assert(t0 == 1); 53 | assert(t1 == 2); 54 | assert(t2 == 3); 55 | 56 | constexpr auto sum = [](shorty::tuple_like auto && tpl) { 57 | return [&](std::index_sequence) { 58 | return (std::get(tpl) + ... + 0); 59 | }(std::make_index_sequence>>()); 60 | }; 61 | 62 | auto test = $(($0, $1, $2, $3)); // double paranthesis are explicit, so we get tuple 63 | auto r2 = test(1, 2, 3, 4); 64 | std::println("{} == 10", r2); 65 | 66 | // identify i; 67 | // expr(1, 2); 68 | // expr(std::tuple{1}); 69 | 70 | // auto expr2 = $lhs + $x; 71 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terser (shorter) lambda == SHORTY 2 | 3 | This library is intended to give terser syntax than C++'s lambdas, not replace C++ with lazy DSL. 4 | 5 | ```c++ 6 | import shorty; 7 | using namespace shorty::literals; 8 | 9 | // you no longer need to remember if it's `std::less` or `std::greater` 10 | std::ranges::sort(subject, $lhs > $rhs); 11 | 12 | // filter only even 13 | subject | std::views::filter(($i % 2) == 0); 14 | 15 | // zip together and transform 16 | std::views::zip(A,B,C,D) | std::views::transform($a * $b + $c * $d); 17 | 18 | // call external function 19 | auto pythagorean = $($a * $a + $b * $b); // or $call; 20 | pythagorean(3.0, 4.0) == 5.0; 21 | 22 | // casting 23 | auto to_int = $($0); // or $cast; 24 | to_int(4.3) == 4; 25 | 26 | // remap by index 27 | auto indices = std::vector{...}; 28 | auto mapping = indices | $(data)[$i]; 29 | ``` 30 | 31 | ## accessing arguments 32 | 33 | If shorty callable gets only one argument and the argument is `tuple_like` then it's automatically unwrapped. Same applies to any lazy calls. 34 | 35 | By default arguments are accessible using `$0`...`$9` syntax (for first 10) or `$arg`. But also you can use following special arguments: 36 | 37 | - `$lhs` and `$rhs` for binary callables (it limits them to two arguments) 38 | - `$it` for first and only argument, which is also compatible with `std::input_or_output_iterator` 39 | - `$a` ... `$f` for first 6 arguments but names instead of numbers (can't be mixed with other types of arguments) 40 | - `$x`, `$y`, `$z` for first 3 arguments (again can't be mixed with other types of arguments) 41 | - `$i`, `$n`, `$k`, `$in` ... for first and only argument (can't be mixed too) 42 | 43 | ## querying arguments 44 | 45 | - `$argc` for getting number of arguments as `size_t` 46 | - `$args` to get all arguments as a tuple 47 | 48 | ## capturing 49 | 50 | - `$(v)` or `$ref(v)` capture by reference (or const reference, depending on const qualifier of `v`) 51 | - `$value(v)`, `$val(v)`, or `$copy(v)` capture by copy 52 | - `$fixed` or `$const` capture by CNTTP (only for structural types) 53 | 54 | ## calling functions 55 | 56 | - `$(args...)` or `$call(args...)` call `callable` with arguments `args` 57 | - `$(args...)` or `$call(args...)` call new instance of type `CallableType` with arguments `args` 58 | 59 | ## casting 60 | 61 | - `$(expr)` or `$cast(expr)` will `static_cast` expression result into `T` 62 | 63 | ## making a tuple 64 | 65 | - `($a, $b, $c)` - will make `tuple` 66 | - `($0, $1)` - will make `tuple` 67 | 68 | ## assigning 69 | 70 | - `$a += 2` will add 2 to `$a` and return result 71 | - `-=`, `*=`, `/=`, `%=` all works too 72 | 73 | ---- 74 | 75 | Special thanks (and a bit of hate) to an [anonymous Argentinian](https://bsky.app/profile/kaballo86.bsky.social) for nerd-sniping into this. 76 | -------------------------------------------------------------------------------- /cmake/coverage.cmake: -------------------------------------------------------------------------------- 1 | SET(test_source "int main() { }") 2 | 3 | try_compile(COVERAGE_WORKS SOURCE_FROM_VAR test.cpp test_source LINK_OPTIONS -fprofile-instr-generate -fcoverage-mapping OUTPUT_VARIABLE COVERAGE_WORKS_OUTPUT) 4 | 5 | if (NOT COVERAGE_WORKS) 6 | #message(STATUS "test coverage is not compatible with current compiler") 7 | #message(STATUS "${COVERAGE_WORKS_OUTPUT}") 8 | function(enable_coverage) 9 | endfunction() 10 | 11 | function(coverage_report_after EVENT TARGET) 12 | add_custom_target(coverage DEPENDS ${EVENT}) 13 | endfunction() 14 | 15 | unset(LLVM_COV) 16 | return() 17 | endif() 18 | 19 | cmake_path(GET CMAKE_CXX_COMPILER PARENT_PATH COMPILER_HINT_PATH) 20 | 21 | if (NOT LLVM_PROFDATA) 22 | find_program(LLVM_PROFDATA llvm-profdata HINTS ${COMPILER_HINT_PATH}) 23 | endif() 24 | 25 | if (NOT LLVM_COV) 26 | find_program(LLVM_COV llvm-cov HINTS ${COMPILER_HINT_PATH}) 27 | endif() 28 | 29 | if (LLVM_PROFDATA AND LLVM_COV) 30 | set(LLVM_PROFDATA "${LLVM_PROFDATA}" CACHE INTERNAL "path to llvm-profdata") 31 | set(LLVM_COV "${LLVM_COV}" CACHE INTERNAL "path to llvm-cov") 32 | else() 33 | find_program(XCRUN xcrun) 34 | if (XCRUN) 35 | set(LLVM_PROFDATA "${XCRUN} llvm-profdata" CACHE INTERNAL "path to llvm-profdata") 36 | set(LLVM_COV "${XCRUN} llvm-cov" CACHE INTERNAL "path to llvm-cov") 37 | endif() 38 | endif() 39 | 40 | find_program(OPEN_UTILITY open) 41 | set(OPEN_UTILITY "${OPEN_UTILITY}" CACHE INTERNAL "path to open utility") 42 | 43 | function(enable_coverage) 44 | 45 | if (NOT COVERAGE_WORKS) 46 | message(FATAL_ERROR "Source level code coverage is not supporter!") 47 | endif() 48 | 49 | if (NOT LLVM_COV) 50 | message(FATAL_ERROR "Source level code coverage is supported only for Clang compiler! (CMAKE_CXX_COMPILER_ID = ${CMAKE_CXX_COMPILER_ID})") 51 | endif() 52 | 53 | message(STATUS "Enabling Clang source code-coverage (llvm-cov=${LLVM_COV})") 54 | 55 | # add flags to emit coverage 56 | add_compile_options("-fprofile-instr-generate" "-fcoverage-mapping" "-g") 57 | add_link_options("-fprofile-instr-generate" "-fcoverage-mapping") 58 | add_compile_options("-ffile-prefix-map=${CMAKE_SOURCE_DIR}/=/") 59 | endfunction() 60 | 61 | function(coverage_report_after EVENT TARGET) 62 | if (NOT LLVM_COV) 63 | add_custom_target(coverage DEPENDS ${EVENT}) 64 | return() 65 | endif() 66 | 67 | SET(coverage_data_name "default.profraw") 68 | add_custom_command(TARGET ${EVENT} POST_BUILD 69 | COMMAND ${LLVM_PROFDATA} merge -sparse ${coverage_data_name} -o coverage.profdata 70 | COMMAND ${LLVM_COV} show $ -format html -instr-profile=coverage.profdata "-ignore-filename-regex=\"(external/.*|tests/.*|cthash/internal/assert[.]hpp)\"" -output-dir ${CMAKE_BINARY_DIR}/report -show-instantiations=false -show-directory-coverage -show-expansions=false -show-line-counts --show-line-counts-or-regions -Xdemangler c++filt -Xdemangler -n -show-branches=percent -tab-size=4 -path-equivalence=/,${CMAKE_SOURCE_DIR} 71 | COMMAND cd ${CMAKE_BINARY_DIR} && zip -q -r -9 report.zip report BYPRODUCTS ${CMAKE_BINARY_DIR}/report.zip COMMENT "Generating Code-Coverage report" 72 | ) 73 | 74 | add_custom_target(coverage DEPENDS ${CMAKE_BINARY_DIR}/report.zip) 75 | 76 | if (OPEN_UTILITY) 77 | add_custom_command(TARGET coverage POST_BUILD COMMAND ${OPEN_UTILITY} ${CMAKE_BINARY_DIR}/report/index.html DEPENDS ${CMAKE_BINARY_DIR}/report.zip) 78 | endif() 79 | endfunction() 80 | -------------------------------------------------------------------------------- /source/shorty/literals.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SHORTY_SHORTY_LITERALS_HPP 2 | #define SHORTY_SHORTY_LITERALS_HPP 3 | 4 | #ifdef SHORTY_IS_IN_MODULE 5 | #define SHORTY_EXPORT export 6 | #else // SHORTY_IS_IN_MODULE 7 | #include "leaves.hpp" 8 | #define SHORTY_EXPORT 9 | #endif // SHORTY_IS_IN_MODULE 10 | 11 | SHORTY_EXPORT namespace shorty::literals { 12 | template constexpr auto $arg = shorty::nth_argument{}; 13 | 14 | constexpr auto $args = shorty::pack_arguments{}; 15 | constexpr auto $argc = shorty::argument_count{}; 16 | // constexpr auto $unused = shorty::argument_unused{}; all unused arguments will wrap into a tuple 17 | 18 | // nth-argument 19 | constexpr auto $0 = $arg<0>; 20 | constexpr auto $1 = $arg<1>; 21 | constexpr auto $2 = $arg<2>; 22 | constexpr auto $3 = $arg<3>; 23 | constexpr auto $4 = $arg<4>; 24 | constexpr auto $5 = $arg<5>; 25 | constexpr auto $6 = $arg<6>; 26 | constexpr auto $7 = $arg<7>; 27 | constexpr auto $8 = $arg<8>; 28 | constexpr auto $9 = $arg<9>; 29 | 30 | // #if __cpp_template_parameters >= 202502L 31 | // template