initial commit
This commit is contained in:
commit
75799f4652
9 changed files with 316 additions and 0 deletions
57
CMakeLists.txt
Normal file
57
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# xo-stringliteral/CMakeLists.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(xo_stringliteral VERSION 1.0)
|
||||
enable_language(CXX)
|
||||
|
||||
# common XO cmake macros (see proj/xo-cmake)
|
||||
include(cmake/xo-bootstrap-macros.cmake)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# unit test setup
|
||||
|
||||
enable_testing()
|
||||
# activate code coverage for all executables + libraries (when configured with -DCODE_COVERAGE=ON)
|
||||
add_code_coverage()
|
||||
|
||||
# 1. assuming that /nix/store/ prefixes .hpp files belonging to gcc, catch2 etc.
|
||||
# we're not interested in code coverage for these sources.
|
||||
# 2. exclude the utest/ subdir, we don't need coverage on the unit tests themselves;
|
||||
# rather, want coverage on the code that the unit tests exercise.
|
||||
#
|
||||
# NOTE: this seems to work only with the 'ccov-all' target. In particular, doesn't seem to do anything with the 'ccov' target
|
||||
#
|
||||
add_code_coverage_all_targets(EXCLUDE /nix/store/* ${PROJECT_SOURCE_DIR}/utest/* ${PROJECT_BINARY_DIR}/local/* ${PROJECT_SOURCE_DIR}/repo/*)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# c++ settings
|
||||
|
||||
# one-time project-specific c++ flags. usually empty
|
||||
set(PROJECT_CXX_FLAGS "")
|
||||
#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2")
|
||||
add_definitions(${PROJECT_CXX_FLAGS})
|
||||
|
||||
xo_toplevel_compile_options()
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
add_subdirectory(example)
|
||||
#add_subdirectory(utest)
|
||||
#add_subdirectory(docs)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# provide find_package() support for projects using this library
|
||||
|
||||
set(SELF_LIB xo_stringliteral)
|
||||
xo_add_headeronly_library(${SELF_LIB})
|
||||
xo_install_library4(${SELF_LIB} ${PROJECT_NAME}Targets)
|
||||
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# dependencies
|
||||
|
||||
#xo_headeronly_dependency(${SELF_LIB} randomgen)
|
||||
# etc..
|
||||
|
||||
# end CMakeLists.txt
|
||||
26
cmake/xo-bootstrap-macros.cmake
Normal file
26
cmake/xo-bootstrap-macros.cmake
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# ----------------------------------------------------------------
|
||||
# for example use
|
||||
# $ PREFIX=/usr/local # for example
|
||||
# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build
|
||||
#
|
||||
# will set
|
||||
# CMAKE_MODULE_PATH = /usr/local/share/cmake
|
||||
# and expect .cmake macros in
|
||||
# /usr/local/share/cmake/xo_macros/xo-project-macros.cmake
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix))
|
||||
# default to typical install location for xo-project-macros
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/cmake)
|
||||
endif()
|
||||
|
||||
if (NOT XO_SUBMODULE_BUILD)
|
||||
message("-- GUESSED_CMAKE_CMD=cmake -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -B ${CMAKE_BINARY_DIR}")
|
||||
message("-- CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
|
||||
message("-- CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
|
||||
endif()
|
||||
|
||||
# needs to have been installed somewhere on CMAKE_MODULE_PATH,
|
||||
# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX)
|
||||
#
|
||||
include(xo_macros/xo-project-macros)
|
||||
17
cmake/xo_stringliteralConfig.cmake.in
Normal file
17
cmake/xo_stringliteralConfig.cmake.in
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
# note: changes to find_dependency() calls here
|
||||
# must coordinate with xo_dependency() calls
|
||||
# in xo-reactor/src/reactor/CMakeLists.txt
|
||||
#
|
||||
#find_dependency(reflect)
|
||||
#find_dependency(subsys)
|
||||
#find_dependency(Eigen3)
|
||||
#find_dependency(webutil)
|
||||
#find_dependency(printjson)
|
||||
#find_dependency(callback)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
1
example/CMakeLists.txt
Normal file
1
example/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(ex1)
|
||||
15
example/ex1/CMakeLists.txt
Normal file
15
example/ex1/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# xo-stringliteral/example/ex1/CMakeLists.txt
|
||||
|
||||
set(SELF_EXE xo_stringliteral_ex1)
|
||||
set(SELF_SRCS ex1.cpp)
|
||||
|
||||
add_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_include_options2(${SELF_EXE})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# dependencies..
|
||||
|
||||
xo_self_dependency(${SELF_EXE} xo_stringliteral)
|
||||
#xo_dependency(${SELF_EXE} reflect)
|
||||
|
||||
# end CMakeLists.txt
|
||||
38
example/ex1/ex1.cpp
Normal file
38
example/ex1/ex1.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* @file ex1.cpp */
|
||||
|
||||
#include "xo/stringliteral/stringliteral.hpp"
|
||||
#include "xo/stringliteral/stringliteral_iostream.hpp"
|
||||
#include "xo/stringliteral/string_view_concat.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int
|
||||
main() {
|
||||
using namespace std;
|
||||
using xo::stringliteral;
|
||||
using xo::stringliteral_compare;
|
||||
|
||||
#ifdef NOT_USING
|
||||
constexpr stringliteral s1("hello");
|
||||
|
||||
static_assert(stringliteral_compare(s1, s1) == 0);
|
||||
|
||||
cerr << s1 << endl;
|
||||
|
||||
constexpr stringliteral s2 = stringliteral_concat(stringliteral("hello"),
|
||||
stringliteral(", world"));
|
||||
|
||||
#endif
|
||||
|
||||
static constexpr string_view hello("hello");
|
||||
static constexpr string_view world(" world");
|
||||
|
||||
static constexpr auto s2 = concat_v<hello, world>;
|
||||
|
||||
static constexpr string_view hello_world("hello world");
|
||||
|
||||
static_assert(s2 == hello_world);
|
||||
|
||||
cerr << hello_world << endl;
|
||||
}
|
||||
|
||||
/* end ex1.cpp */
|
||||
30
include/xo/stringliteral/string_view_concat.hpp
Normal file
30
include/xo/stringliteral/string_view_concat.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <string_view>
|
||||
#include <array>
|
||||
|
||||
template <std::string_view const & ... Strings>
|
||||
struct sv_concat
|
||||
{
|
||||
static constexpr auto impl() noexcept {
|
||||
constexpr std::size_t n = (Strings.size() + ... + 0);
|
||||
|
||||
std::array<char, n + 1> arr{};
|
||||
|
||||
auto append = [i=0, &arr](const auto & s) mutable {
|
||||
for (auto c : s)
|
||||
arr[i++] = c;
|
||||
};
|
||||
(append(Strings), ...);
|
||||
arr[n] = '\0';
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
static constexpr auto arr = impl();
|
||||
static constexpr std::string_view value {
|
||||
arr.data(),
|
||||
arr.size() - 1
|
||||
};
|
||||
};
|
||||
|
||||
template <std::string_view const & ... Strings>
|
||||
static constexpr auto concat_v = sv_concat<Strings...>::value;
|
||||
96
include/xo/stringliteral/stringliteral.hpp
Normal file
96
include/xo/stringliteral/stringliteral.hpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/** @file stringliteral.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
/** @class stringliteral
|
||||
*
|
||||
* @brief class to represent a literal string at compile time, for use as template argument
|
||||
**/
|
||||
template <std::size_t N>
|
||||
struct stringliteral {
|
||||
constexpr stringliteral() { if (N > 0) value_[0] = '\0'; }
|
||||
constexpr stringliteral(const char (&str)[N]) { std::copy_n(str, N, value_); }
|
||||
constexpr int size() const { return N; }
|
||||
|
||||
constexpr char const * c_str() const { return value_; }
|
||||
|
||||
char value_[N];
|
||||
};
|
||||
|
||||
/** @brief all_same_v<T1, .., Tn> is true iff types T1 = .. = Tn
|
||||
**/
|
||||
template < typename First, typename... Rest >
|
||||
constexpr auto
|
||||
all_same_v = std::conjunction_v< std::is_same<First, Rest>... >;
|
||||
|
||||
/** @brief concatenate string literals
|
||||
*
|
||||
* NOTE: this isn't constexpr in clang16
|
||||
**/
|
||||
template < typename... Ts>
|
||||
constexpr auto
|
||||
stringliteral_concat(Ts && ... args)
|
||||
{
|
||||
#ifdef NOT_USING
|
||||
static_assert(all_same_v<std::decay_t<Ts>...>,
|
||||
"string must share the same char type");
|
||||
|
||||
using char_type = std::remove_const_t< std::remove_pointer_t < std::common_type_t < Ts... > > >;
|
||||
#endif
|
||||
using char_type = char;
|
||||
|
||||
/** n1: total number of bytes used by arguments **/
|
||||
constexpr size_t n1 = (sizeof(Ts) + ...);
|
||||
/** z1: each string arg has a null terminator included in its size,
|
||||
* z1 is the number of arguments in parameter pack Ts,
|
||||
* which equals the number of null terminators used
|
||||
**/
|
||||
constexpr size_t z1 = sizeof...(Ts);
|
||||
|
||||
/** n: number of chars in concatenated string. +1 for final null **/
|
||||
constexpr size_t n
|
||||
= (n1 / sizeof(char_type)) - z1 + 1;
|
||||
|
||||
stringliteral<n> result;
|
||||
size_t pos = 0;
|
||||
|
||||
auto detail_concat = [ &pos, &result ](auto && arg) {
|
||||
constexpr auto count = (sizeof(arg) - sizeof(char_type)) / sizeof(char_type);
|
||||
|
||||
std::copy_n(arg.c_str(), count, result.value_ + pos);
|
||||
pos += count;
|
||||
};
|
||||
|
||||
(detail_concat(args), ...);
|
||||
|
||||
//return stringliteral("");
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef NOT_USING
|
||||
template <std::size_t N1, std::size_t N2>
|
||||
constexpr auto
|
||||
stringliteral_compare(stringliteral<N1> && s1, stringliteral<N2> && s2)
|
||||
{
|
||||
return std::string_view(s1.value_) <=> std::string_view(s2.value_);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <std::size_t N1, std::size_t N2>
|
||||
constexpr auto
|
||||
stringliteral_compare(const stringliteral<N1> & s1, const stringliteral<N2> & s2)
|
||||
{
|
||||
return std::string_view(s1.value_) <=> std::string_view(s2.value_);
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/** end stringliteral.hpp **/
|
||||
36
include/xo/stringliteral/stringliteral_iostream.hpp
Normal file
36
include/xo/stringliteral/stringliteral_iostream.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/** @file stringliteral_iostream.hpp
|
||||
*
|
||||
* Author: Roland Conybeare
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stringliteral.hpp"
|
||||
#include <ostream>
|
||||
//#include <cstdint>
|
||||
|
||||
namespace xo {
|
||||
/** @brief print stringliteral on stream os.
|
||||
*
|
||||
**/
|
||||
template <std::size_t N>
|
||||
void
|
||||
print_stringliteral (std::ostream & os, const stringliteral<N> & x) {
|
||||
os << x.c_str();
|
||||
}
|
||||
|
||||
/** @brief print stringliteral x on stream os.
|
||||
*
|
||||
* Example
|
||||
* @code
|
||||
* cout << stringliteral("foo"); // outputs "foo"
|
||||
**/
|
||||
template <std::size_t N>
|
||||
inline std::ostream &
|
||||
operator<< (std::ostream & os, const stringliteral<N> & x) {
|
||||
print_stringliteral(os, x);
|
||||
return os;
|
||||
}
|
||||
} /*namespace xo*/
|
||||
|
||||
/** end stringliteral_iostream.hpp **/
|
||||
Loading…
Add table
Add a link
Reference in a new issue