diff --git a/.circleci/config.yml b/.circleci/config.yml index 3693ac0e..a325f692 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,6 +7,9 @@ orbs: commands: run-cibuildwheel: parameters: + cibw-config: # environment variables + type: string + default: "" cibw-version: type: string default: 4.2.0 # latest as of August 2026 @@ -16,7 +19,7 @@ commands: shell: bash -eo pipefail command: | python -m pip install --user cibuildwheel==<< parameters.cibw-version >> - python -m cibuildwheel --output-dir dist + << parameters.cibw-config >> python -m cibuildwheel --output-dir dist - store_artifacts: &store-artifacts path: ./dist @@ -122,7 +125,9 @@ jobs: steps: - checkout - - run-cibuildwheel + - run: choco install llvm -y + - run-cibuildwheel: + cibw-config: CIBW_ENVIRONMENT_PASS=CXX CXX=clang-cl python-sdist: docker: @@ -407,7 +412,7 @@ workflows: name: cpp-gcc-<< matrix.gcc-version >> matrix: parameters: - gcc-version: ["12", "latest"] + gcc-version: ["14", "latest"] - cpp-macOS - serialization: requires: diff --git a/dwave/optimization/include/dwave-optimization/common.hpp b/dwave/optimization/include/dwave-optimization/common.hpp index bcbf7898..07344982 100644 --- a/dwave/optimization/include/dwave-optimization/common.hpp +++ b/dwave/optimization/include/dwave-optimization/common.hpp @@ -32,16 +32,3 @@ typedef std::int64_t ssize_t; #include // for ssize_t #endif - -namespace dwave::optimization { - -// backport unreachable from c++23 -[[noreturn]] inline void unreachable() { -#if defined(_MSC_VER) && !defined(__clang__) // MSVC - __assume(false); -#else // GCC, Clang - __builtin_unreachable(); -#endif -} - -} // namespace dwave::optimization diff --git a/dwave/optimization/include/dwave-optimization/iterators.hpp b/dwave/optimization/include/dwave-optimization/iterators.hpp index f547459f..4ec2b545 100644 --- a/dwave/optimization/include/dwave-optimization/iterators.hpp +++ b/dwave/optimization/include/dwave-optimization/iterators.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "dwave-optimization/common.hpp" // for ssize_t #include "dwave-optimization/typing.hpp" @@ -461,7 +462,7 @@ requires( case FormatCharacter::signedlonglong_: return *static_cast(ptr); } - unreachable(); + std::unreachable(); } } diff --git a/dwave/optimization/include/dwave-optimization/nodes/testing.hpp b/dwave/optimization/include/dwave-optimization/nodes/testing.hpp index 3954ff67..d079d00e 100644 --- a/dwave/optimization/include/dwave-optimization/nodes/testing.hpp +++ b/dwave/optimization/include/dwave-optimization/nodes/testing.hpp @@ -16,6 +16,7 @@ #include #include +#include #include #include "dwave-optimization/array.hpp" @@ -113,18 +114,18 @@ class DynamicArrayTestingNode : public ArrayOutputMixin, public Decis checkpoint_type& checkpoint ) const override { assert(false and "not implemented"); - unreachable(); + std::unreachable(); } [[noreturn]] void assign_from_checkpoint( State& state, checkpoint_type&& checkpoint ) const override { assert(false and "not implemented"); - unreachable(); + std::unreachable(); } [[noreturn]] virtual checkpoint_type checkpoint(State& state) const override { assert(false and "not implemented"); - unreachable(); + std::unreachable(); } // State mutation methods ************************************************* @@ -185,7 +186,7 @@ class DynamicArrayTestingNode : public ArrayOutputMixin, public Decis case 2: return set(state, rng); default: - unreachable(); + std::unreachable(); } } diff --git a/dwave/optimization/src/array.cpp b/dwave/optimization/src/array.cpp index 3484d30c..5f897f4d 100644 --- a/dwave/optimization/src/array.cpp +++ b/dwave/optimization/src/array.cpp @@ -241,8 +241,6 @@ std::vector broadcast_shapes( std::vector shape(std::max(lhs.size(), rhs.size())); // Walk backwards through the shapes, checking for dimension compatibility. - // Technically span::rbegin() etc are c++23 features but it seems to work on - // all the compilers we care about. Whereas the c++20 ranges::rbegin() etc do not. auto lit = lhs.rbegin(); const auto lend = lhs.rend(); auto rit = rhs.rbegin(); diff --git a/dwave/optimization/src/nodes/binaryop.cpp b/dwave/optimization/src/nodes/binaryop.cpp index 78ee6535..5f3279b3 100644 --- a/dwave/optimization/src/nodes/binaryop.cpp +++ b/dwave/optimization/src/nodes/binaryop.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "_state.hpp" @@ -151,7 +152,7 @@ std::pair calculate_values_minmax(const Array* lhs_ptr, const Ar } assert(false && "not implemeted yet"); - unreachable(); + std::unreachable(); } template @@ -182,7 +183,7 @@ bool calculate_integral(const Array* lhs_ptr, const Array* rhs_ptr) { } assert(false && "not implemeted yet"); - unreachable(); + std::unreachable(); } template @@ -294,7 +295,7 @@ void BinaryOpNode::initialize_state(State& state) const { } else { // this case is complicated we need to "stretch" dimensions into each other assert(false && "not yet implemented"); - unreachable(); + std::unreachable(); } this->template emplace_data_ptr_(state, std::move(values)); @@ -427,7 +428,7 @@ void BinaryOpNode::propagate(State& state) const { } else { // this case is complicated we need to "stretch" dimensions into eachother assert(false && "not yet implemented"); - unreachable(); + std::unreachable(); } if (ptr->diff().size()) Node::propagate(state); @@ -512,7 +513,7 @@ SizeInfo binaryop_calculate_sizeinfo( // not possible for us to be dynamic and none of our predecessors to be assert(false && "not implemeted"); - unreachable(); + std::unreachable(); } template diff --git a/dwave/optimization/src/nodes/collections.cpp b/dwave/optimization/src/nodes/collections.cpp index bee598ca..099553ff 100644 --- a/dwave/optimization/src/nodes/collections.cpp +++ b/dwave/optimization/src/nodes/collections.cpp @@ -532,7 +532,7 @@ struct DisjointBitSetsNodeData_ : CheckpointableState, NodeStateData { } assert(false and "disjoint set elements must be in exactly one bit-set once"); - unreachable(); + std::unreachable(); } void commit() { diff --git a/dwave/optimization/src/nodes/creation.cpp b/dwave/optimization/src/nodes/creation.cpp index 492ece3a..9d7cf54e 100644 --- a/dwave/optimization/src/nodes/creation.cpp +++ b/dwave/optimization/src/nodes/creation.cpp @@ -14,6 +14,7 @@ #include "dwave-optimization/nodes/creation.hpp" +#include #include #include "_state.hpp" @@ -109,7 +110,7 @@ std::vector arange(const ssize_t start, const ssize_t stop, const ssize_ } } else { assert(false && "0 step not allowed"); - unreachable(); + std::unreachable(); } return arange; @@ -178,7 +179,7 @@ std::pair calculate_values_minmax( } assert(false && "zero step not allowed"); - unreachable(); + std::unreachable(); } const SizeInfo calculate_arange_sizeinfo( @@ -226,7 +227,7 @@ const SizeInfo calculate_arange_sizeinfo( ); } else { assert(false && "unreachable"); - unreachable(); + std::unreachable(); } // Handles all cases EXCEPT the following: "Exactly one predecessor, it @@ -423,7 +424,7 @@ void ARangeNode::propagate(State& state) const { } } else { assert(false && "zero step not allowed"); - unreachable(); + std::unreachable(); } if (ptr->diff().size()) Node::propagate(state); diff --git a/dwave/optimization/src/nodes/flow.cpp b/dwave/optimization/src/nodes/flow.cpp index 52dc5847..0776410b 100644 --- a/dwave/optimization/src/nodes/flow.cpp +++ b/dwave/optimization/src/nodes/flow.cpp @@ -301,13 +301,8 @@ void WhereNode::initialize_state(State& state) const { std::vector values; values.reserve(condition.size()); - // zip would be very nice here... - for ( - auto cit = condition.begin(), xit = x.begin(), yit = y.begin(); - cit != std::default_sentinel; - ++cit, ++xit, ++yit - ) { - values.emplace_back((*cit) ? *xit : *yit); + for (const auto& [ci, xi, yi] : std::views::zip(condition, x, y)) { + values.emplace_back(ci ? xi : yi); } emplace_data_ptr_(state, std::move(values)); diff --git a/dwave/optimization/src/nodes/indexing.cpp b/dwave/optimization/src/nodes/indexing.cpp index 87988074..47542a91 100644 --- a/dwave/optimization/src/nodes/indexing.cpp +++ b/dwave/optimization/src/nodes/indexing.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "_state.hpp" @@ -781,7 +782,7 @@ void AdvancedIndexingNode::replace_predecessor_(ssize_t index, Node* node_ptr) { } assert(false and "should not be able to get here"); - unreachable(); + std::unreachable(); } void AdvancedIndexingNode::revert(State& state) const { @@ -1405,13 +1406,13 @@ SizeInfo basicindexing_calculate_sizeinfo( } else if (start < 0 && stop >= 0) { // -start:stop:step - imposes a nonlinear maximum size assert(false && "not linear, handled above"); - unreachable(); + std::unreachable(); } else if (start < 0 && stop < 0) { // -start:-stop:step - imposes a maximum size sizeinfo.max = num_per_row * (std::max(stop - start, 0) + step - 1) / step; } else { assert(false && "shouldn't be reachable"); - unreachable(); + std::unreachable(); } } diff --git a/dwave/optimization/src/nodes/lambda.cpp b/dwave/optimization/src/nodes/lambda.cpp index b40ec9a5..75c87561 100644 --- a/dwave/optimization/src/nodes/lambda.cpp +++ b/dwave/optimization/src/nodes/lambda.cpp @@ -14,6 +14,8 @@ #include "dwave-optimization/nodes/lambda.hpp" +#include + #include "_state.hpp" #include "dwave-optimization/array.hpp" #include "dwave-optimization/graph.hpp" @@ -352,7 +354,7 @@ void AccumulateZipNode::propagate(State& state) const { data->emplace_back(val); } else { assert(false && "index is too large for current buffer"); - unreachable(); + std::unreachable(); } } diff --git a/dwave/optimization/src/nodes/lp.cpp b/dwave/optimization/src/nodes/lp.cpp index b1f06f2c..1ab60b83 100644 --- a/dwave/optimization/src/nodes/lp.cpp +++ b/dwave/optimization/src/nodes/lp.cpp @@ -15,6 +15,7 @@ #include "dwave-optimization/nodes/lp.hpp" #include +#include #include "../simplex.hpp" #include "_state.hpp" @@ -433,7 +434,7 @@ void LinearProgramNode::replace_predecessor_(ssize_t index, Node* node_ptr) { if (check_and_replace(lb_ptr_)) return; if (check_and_replace(ub_ptr_)) return; - unreachable(); + std::unreachable(); assert(false and "should never get here"); } diff --git a/dwave/optimization/src/nodes/manipulation.cpp b/dwave/optimization/src/nodes/manipulation.cpp index 1c45621f..b4b2f063 100644 --- a/dwave/optimization/src/nodes/manipulation.cpp +++ b/dwave/optimization/src/nodes/manipulation.cpp @@ -1193,14 +1193,7 @@ void ResizeNode::initialize_state(State& state) const { const ssize_t size = this->size(); // the desired size of our state assert(size >= 0); // we're never dynamic - std::vector values; - values.reserve(size); - - // Fill in from our predecessor, up to our size. - // In c++23 we could use append_range(...) which would be nicer. - for (const auto& v : array_ptr_->view(state) | std::views::take(size)) { - values.emplace_back(v); - } + auto values = std::ranges::to(array_ptr_->view(state) | std::views::take(size)); // Now fill in everything else with our fill value assert( diff --git a/dwave/optimization/src/nodes/naryop.cpp b/dwave/optimization/src/nodes/naryop.cpp index 5dc47e48..150337f1 100644 --- a/dwave/optimization/src/nodes/naryop.cpp +++ b/dwave/optimization/src/nodes/naryop.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "_state.hpp" @@ -83,7 +84,7 @@ bool calculate_integral(const std::vector& operands) { } assert(false && "not implemeted yet"); - unreachable(); + std::unreachable(); } template @@ -142,7 +143,7 @@ ValuesInfo calculate_values_info(const std::vector& operands) { } assert(false && "not implemeted yet"); - unreachable(); + std::unreachable(); } template diff --git a/dwave/optimization/src/nodes/numbers.cpp b/dwave/optimization/src/nodes/numbers.cpp index bed90025..a12d667c 100644 --- a/dwave/optimization/src/nodes/numbers.cpp +++ b/dwave/optimization/src/nodes/numbers.cpp @@ -502,7 +502,7 @@ bool satisfies_sum_constraint( break; default: assert(false && "Unexpected operator type."); - unreachable(); + std::unreachable(); } } } @@ -593,7 +593,7 @@ double sum_constraint_delta( return (lhs < bound) ? (bound - lhs) : 0.0; default: assert(false && "Unexpected operator type."); - unreachable(); + std::unreachable(); } } @@ -717,7 +717,7 @@ void NumberNode::initialize_state(State& state) const { initialize_state(state, std::move(values)); } else { assert(false && "Multiple sum constraints not yet supported."); - unreachable(); + std::unreachable(); } } @@ -1608,7 +1608,7 @@ void BinaryNode::initialize_state(State& state) const { initialize_state(state, std::move(values)); } else { assert(false && "Multiple sum constraints not yet supported."); - unreachable(); + std::unreachable(); } } diff --git a/dwave/optimization/src/nodes/unaryop.cpp b/dwave/optimization/src/nodes/unaryop.cpp index 73902761..d871be91 100644 --- a/dwave/optimization/src/nodes/unaryop.cpp +++ b/dwave/optimization/src/nodes/unaryop.cpp @@ -14,6 +14,8 @@ #include "dwave-optimization/nodes/unaryop.hpp" +#include + #include "_state.hpp" namespace dwave::optimization { @@ -58,7 +60,7 @@ std::pair calculate_values_minmax(const Array* array_ptr) { return std::make_pair(low, high); } else if (low >= 0) { assert(false && "min > max"); - unreachable(); + std::unreachable(); } else if (high >= 0) { return std::pair(0.0, std::max(-low, high)); } else { @@ -99,7 +101,7 @@ std::pair calculate_values_minmax(const Array* array_ptr) { } assert(false && "not implemeted yet"); - unreachable(); + std::unreachable(); } template diff --git a/meson.build b/meson.build index b8882ec8..1e64bf33 100644 --- a/meson.build +++ b/meson.build @@ -2,7 +2,7 @@ project( 'dwave-optimization', 'c', 'cpp', 'cython', default_options: [ - 'cpp_std=c++20', + 'cpp_std=c++23', 'buildtype=release', 'b_ndebug=if-release', # add -DNDEBUG when building for "release", which we do by default 'optimization=3', @@ -19,12 +19,14 @@ project( ).stdout(), ) -# We want some debugging symbols -add_project_arguments(['-g1'], language: ['cpp']) - cpp = meson.get_compiler('cpp') py = import('python').find_installation(pure: false) +# We want some debugging symbols +if cpp.has_argument('-g1') + add_project_arguments('-g1', language: 'cpp') +endif + dwave_optimization_include = include_directories('dwave/optimization/include/') dwave_optimization_src = [ 'dwave/optimization/src/nodes/_checkpoints.cpp', diff --git a/releasenotes/notes/c++23-60fb26a150a004e8.yaml b/releasenotes/notes/c++23-60fb26a150a004e8.yaml new file mode 100644 index 00000000..01b4b7bd --- /dev/null +++ b/releasenotes/notes/c++23-60fb26a150a004e8.yaml @@ -0,0 +1,7 @@ +--- +features: + - Compile C++ library with C++23. +upgrade: + - Drop support for GCC<14. +other: + - Build Windows wheels with LLVM rather than MSVC.