From 768fa5b49f41296bc3c0d3c1aae73a34a07ea516 Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Sun, 26 Nov 2023 13:24:38 +0800 Subject: [PATCH] ci --- .github/workflows/ci.yml | 35 ------------------- .github/workflows/linux.yml | 60 +++++++++++++++++++++++++++++++ .github/workflows/macos.yml | 56 +++++++++++++++++++++++++++++ .pre-commit-config.yaml | 6 ++++ CMakeLists.txt | 10 ++++-- conanfile.txt | 35 +++++++++++++++++++ inc/nova/symbol/symbol.hpp | 35 ++++++++++++++++++- src/nova/symbol/symbol.cpp | 70 ++++++++++++++++++++++++++++++++----- test/symbol_test.cpp | 9 +++++ 9 files changed, 269 insertions(+), 47 deletions(-) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/linux.yml create mode 100644 .github/workflows/macos.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 7a1e4dc..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: CMake Build and Test - -on: - push: - branches: - - master - - develop - - githubactions* - - feature/** - - fix/** - - pr/** -jobs: - build-test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ ubuntu-latest, windows-latest, macos-latest ] - - steps: - - uses: actions/checkout@v2 - - - name: Setup CMake - uses: actions/setup-cmake@v3 - with: - cmake-version: '3.18.2' - - - name: Configure CMake - run: cmake . -DCMAKE_BUILD_TYPE=Release -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/conan_provider.cmake - - - name: Build - run: cmake --build build - - - name: Test - run: ctest --build build --target test diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..4903098 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,60 @@ +name: Linux builds + +on: + push: + branches: + - master + - develop + - githubactions* + - feature/** + - fix/** + - pr/** +jobs: + build-test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest] + compiler: [g++-12, g++-13] + + env: + CONAN_USER_HOME: "${{ github.workspace }}/release/" + CONAN_USER_HOME_SHORT: "${{ github.workspace }}/release/short" + + steps: + - uses: actions/checkout@v2 + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.1 + with: + key: ${{ matrix.os }}-${{ matrix.compiler }} + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.1 + with: + key: ${{ matrix.os }}-${{ matrix.compiler }} + + - name: Using the builtin GitHub Cache Action for .conan + id: cache-conan + uses: actions/cache@v1 + env: + cache-name: cache-conan-modules + with: + path: ${{ env.CONAN_USER_HOME }} + key: ${{ runner.os }}-builder-${{ env.cache-name }}-${{ hashFiles('conanfile.txt') }} + restore-keys: ${{ runner.os }}-builder-${{ env.cache-name }} + + - name: Conan installation + id: conan + uses: turtlebrowser/get-conan@v1.0 + + - name: Configure, Build, and Test Project + uses: threeal/cmake-action@v1.3.0 + with: + run-build: true + run-test: true + options: CMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/conan_provider.cmake CMAKE_BUILD_TYPE=Release CMAKE_CXX_COMPILER_LAUNCHER=ccache + + env: + CXX: ${{ matrix.compiler }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 0000000..d55a2b4 --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,56 @@ +name: MacOs builds + +on: + push: + branches: + - master + - develop + - githubactions* + - feature/** + - fix/** + - pr/** +jobs: + build-test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [macos-13] + compiler: ['15.0.1', '14.3.1', '14.2'] + + env: + CONAN_USER_HOME: "${{ github.workspace }}/release/" + CONAN_USER_HOME_SHORT: "${{ github.workspace }}/release/short" + + steps: + - uses: actions/checkout@v2 + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.1 + with: + key: ${{ matrix.os }}-${{ matrix.compiler }} + + - name: Using the builtin GitHub Cache Action for .conan + id: cache-conan + uses: actions/cache@v1 + env: + cache-name: cache-conan-modules + with: + path: ${{ env.CONAN_USER_HOME }} + key: ${{ runner.os }}-builder-${{ env.cache-name }}-${{ hashFiles('conanfile.txt') }} + restore-keys: ${{ runner.os }}-builder-${{ env.cache-name }} + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ matrix.compiler }} + + - name: Conan installation + id: conan + uses: turtlebrowser/get-conan@v1.0 + + - name: Configure, Build, and Test Project + uses: threeal/cmake-action@v1.3.0 + with: + run-build: true + run-test: true + options: CMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/conan_provider.cmake CMAKE_BUILD_TYPE=Release CMAKE_CXX_COMPILER_LAUNCHER=ccache diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2899e97..1908fda 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,3 +15,9 @@ repos: hooks: - id: clang-format types_or: [c++, c, cuda] + +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.27.2 + hooks: + - id: check-github-workflows + args: ["--verbose"] diff --git a/CMakeLists.txt b/CMakeLists.txt index 16e372b..f9272f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,8 @@ add_custom_target(nova_symbol_project_files SOURCES conanfile.txt Readme.md License.txt - .github/workflows/ci.yml + .github/workflows/linux.yml + .github/workflows/macos.yml ) set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS conanfile.txt) @@ -37,13 +38,18 @@ add_library(nova_symbol STATIC ${Sources}) target_include_directories(nova_symbol PUBLIC inc) target_link_libraries(nova_symbol PUBLIC Boost::headers - PRIVATE cityhash::cityhash) + PRIVATE cityhash::cityhash + Boost::container # pmr fallback + ) + ######################################################################################################################## option(NOVA_SYMBOL_BUILD_TEST "Build unit tests" ON) if (NOVA_SYMBOL_BUILD_TEST) + enable_testing() + add_executable(nova_symbol_test test/symbol_test.cpp) add_test(NAME nova_symbol_test COMMAND nova_symbol_test) diff --git a/conanfile.txt b/conanfile.txt index c8eca91..a15e338 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -2,8 +2,43 @@ boost/1.83.0 catch2/3.4.0 cityhash/cci.20130801 + [generators] CMakeDeps CMakeToolchain + [layout] cmake_layout + +[options] +boost*:without_atomic=True +boost*:without_chrono=True +boost*:without_container=False +boost*:without_contract=True +boost*:without_coroutine=True +boost*:without_date_time=True +boost*:without_exception=True +boost*:without_fiber=True +boost*:without_filesystem=True +boost*:without_graph=True +boost*:without_graph_parallel=True +boost*:without_iostreams=True +boost*:without_json=True +boost*:without_locale=True +boost*:without_log=True +boost*:without_math=True +boost*:without_mpi=True +boost*:without_nowide=True +boost*:without_program_options=True +boost*:without_python=True +boost*:without_random=True +boost*:without_regex=True +boost*:without_serialization=True +boost*:without_stacktrace=True +boost*:without_system=True +boost*:without_test=True +boost*:without_thread=True +boost*:without_timer=True +boost*:without_type_erasure=True +boost*:without_url=True +boost*:without_wave=True diff --git a/inc/nova/symbol/symbol.hpp b/inc/nova/symbol/symbol.hpp index dbb4609..dbee6f5 100644 --- a/inc/nova/symbol/symbol.hpp +++ b/inc/nova/symbol/symbol.hpp @@ -23,9 +23,13 @@ // As a non-binding request, please use this code responsibly and ethically. +#include #include +#include -#include +#ifdef __cpp_lib_format +# include +#endif #include @@ -37,6 +41,8 @@ namespace detail { struct symbol_data; } // namespace detail +//---------------------------------------------------------------------------------------------------------------------- + struct string_data_in_persistent_memory_t {}; @@ -57,12 +63,35 @@ struct symbol explicit operator std::string_view() const; auto operator<=>( const symbol& ) const = default; // compare by pointer + uint64_t hash() const; + static uint64_t s_hash( std::string_view ); + private: const detail::symbol_data* data; }; //---------------------------------------------------------------------------------------------------------------------- +#define DEFINE_OPERATOR( OP ) \ + \ + inline auto operator OP( std::string_view lhs, symbol rhs ) \ + { \ + return lhs OP std::string_view { rhs }; \ + } \ + \ + inline auto operator OP( symbol lhs, std::string_view rhs ) \ + { \ + return std::string_view { lhs } OP rhs; \ + } + +DEFINE_OPERATOR( == ) +DEFINE_OPERATOR( != ) +DEFINE_OPERATOR( <=> ) + +#undef DEFINE_OPERATOR + +//---------------------------------------------------------------------------------------------------------------------- + struct lexical_less { bool operator()( const auto& lhs, const auto& rhs ) const @@ -138,6 +167,8 @@ inline symbol operator""_sym( const char* literal, size_t size ) } // namespace nova +#ifdef __cpp_lib_format + template <> struct std::formatter< nova::symbol, char > : std::formatter< std::string_view > { @@ -148,6 +179,8 @@ struct std::formatter< nova::symbol, char > : std::formatter< std::string_view > } }; +#endif + #if __has_include( ) # include diff --git a/src/nova/symbol/symbol.cpp b/src/nova/symbol/symbol.cpp index 8856c88..4eb92ea 100644 --- a/src/nova/symbol/symbol.cpp +++ b/src/nova/symbol/symbol.cpp @@ -2,7 +2,13 @@ #include #include -#include + +#ifdef __cpp_lib_memory_resource +# include +#else +# include +# include +#endif #include @@ -109,19 +115,36 @@ struct compare struct symbol_table { +#ifdef __cpp_lib_memory_resource + using allocator_t = std::pmr::polymorphic_allocator<>; + using monotonic_buffer_resource = std::pmr::monotonic_buffer_resource; +#else + using allocator_t = boost::container::pmr::polymorphic_allocator< void >; + using monotonic_buffer_resource = boost::container::pmr::monotonic_buffer_resource; +#endif + public: ~symbol_table() { - std::pmr::polymorphic_allocator<> allocator { + allocator_t allocator { &memory_resource, }; +#ifdef __cpp_lib_memory_resource table.clear_and_dispose( [ & ]( symbol_data* d ) { if ( d->owns_memory() ) allocator.deallocate_bytes( const_cast< void* >( reinterpret_cast< const void* >( d->str() ) ), d->size() ); allocator.delete_object( d ); } ); +#else + table.clear_and_dispose( [ & ]( symbol_data* d ) { + if ( d->owns_memory() ) + allocator.deallocate( const_cast< void* >( reinterpret_cast< const void* >( d->str() ) ), d->size() ); + d->~symbol_data(); + allocator.deallocate( d, sizeof( symbol_data ) ); + } ); +#endif } const symbol_data* gensym( std::string_view sv ) @@ -132,10 +155,11 @@ struct symbol_table if ( found != table.end() ) return &*found; - std::pmr::polymorphic_allocator<> allocator { + allocator_t allocator { &memory_resource, }; +#ifdef __cpp_lib_memory_resource char* string_data = reinterpret_cast< char* >( allocator.allocate_bytes( sv.size() ) ); std::memcpy( string_data, sv.data(), sv.size() ); @@ -143,6 +167,17 @@ struct symbol_table string_data, sv.size(), } ); +#else + char* string_data = reinterpret_cast< char* >( allocator.allocate( sv.size() ) ); + std::memcpy( string_data, sv.data(), sv.size() ); + + void* chunk = allocator.allocate( sizeof( symbol_data ) ); + auto obj = new ( chunk ) symbol_data( std::string_view { + string_data, + sv.size(), + } ); +#endif + table.insert( *obj ); return obj; } @@ -155,11 +190,17 @@ struct symbol_table if ( found != table.end() ) return &*found; - std::pmr::polymorphic_allocator<> allocator { + allocator_t allocator { &memory_resource, }; +#ifdef __cpp_lib_memory_resource auto obj = allocator.new_object< symbol_data >( sv, pm ); +#else + void* chunk = allocator.allocate( sizeof( symbol_data ) ); + auto obj = new ( chunk ) symbol_data( sv, pm ); +#endif + table.insert( *obj ); return obj; } @@ -175,10 +216,12 @@ struct symbol_table // hash table using hash_table = boost::intrusive::unordered_set< nova::detail::symbol_data, - boost::intrusive::constant_time_size< false >, - boost::intrusive::power_2_buckets< true >, + boost::intrusive::hash< nova::detail::hasher >, - boost::intrusive::equal< nova::detail::compare > >; + boost::intrusive::equal< nova::detail::compare >, + + boost::intrusive::constant_time_size< false >, + boost::intrusive::power_2_buckets< true > >; static constexpr size_t number_of_buckets = 2048; @@ -191,8 +234,7 @@ struct symbol_table static constexpr size_t preallocated_memory = 32 * 1024; alignas( 128 ) std::array< const char*, preallocated_memory > buffer; - - std::pmr::monotonic_buffer_resource memory_resource { + monotonic_buffer_resource memory_resource { buffer.data(), buffer.size(), }; @@ -214,6 +256,16 @@ symbol::operator std::string_view() const return std::string_view( *data ); } +size_t symbol::hash() const +{ + return data->hash(); +} + +uint64_t symbol::s_hash( std::string_view sv ) +{ + return detail::hasher()( sv ); +} + symbol::symbol( std::string_view sv, nova::string_data_in_persistent_memory_t pm ) { data = detail::symbol_table::instance().gensym( sv, pm ); diff --git a/test/symbol_test.cpp b/test/symbol_test.cpp index 1b45f30..782a948 100644 --- a/test/symbol_test.cpp +++ b/test/symbol_test.cpp @@ -21,10 +21,19 @@ TEST_CASE( "symbol" ) CHECK( b != a_2 ); CHECK( b != a_3 ); CHECK( b != a_4 ); + + CHECK( a == "a" ); + CHECK( a == std::string_view( "a" ) ); + CHECK( a == std::string( "a" ) ); } + +#ifdef __cpp_lib_format + TEST_CASE( "format" ) { nova::symbol a( "a" ); CHECK( std::format( "{}", a ) == "a" ); } + +#endif