Skip to content

contracts: add violation handler infrastructure and annotated optional#7129

Draft
Sanchit2662 wants to merge 10 commits intoTheHPXProject:masterfrom
Sanchit2662:poc/contracts-infrastructure
Draft

contracts: add violation handler infrastructure and annotated optional#7129
Sanchit2662 wants to merge 10 commits intoTheHPXProject:masterfrom
Sanchit2662:poc/contracts-infrastructure

Conversation

@Sanchit2662
Copy link
Copy Markdown
Contributor

@Sanchit2662 Sanchit2662 commented Mar 30, 2026

What this is

A standalone, buildable contracts infrastructure - violation handler with enforce/observe/ignore mode dispatch, the macro layer (HPX_CONTRACT_ASSERT, HPX_PRE, HPX_POST), and a minimal optional<T> annotated with P3471 preconditions. Lives in poc/contracts/ and builds independently of HPX's CMake so anyone can run it without a full HPX build.
This is a proof-of-concept : not the real integration, just enough to show the approach is sound.


What I built

Three files that form the core of what the full project would need:

  • violation_handler.hpp - a violation_info struct that mirrors what std::contract_violation will look like in C++26, plus a customizable handler (default: log to stderr + abort). This is the same pattern HPX already uses for assertion_handler.

  • contract_macros.hpp - HPX_CONTRACT_ASSERT, HPX_PRE, HPX_POST macros that dispatch to the right behavior depending on a compile-time mode flag.

  • annotated_optional.hpp - a minimal optional<T> with HPX_CONTRACT_ASSERT(has_value()) on operator*, operator->, and value() - exactly the P3471 preconditions, and exactly what was done in the real optional.hpp on the feat/contracts-optional-operator-star branch.

Plus a contracts_poc.cpp with 20 tests that run across all three modes and a CMakeLists.txt that builds all three at once.


How it works

The key idea is compile-time mode selection:

  • -DHPX_CONTRACTS_MODE=0 → ENFORCE: check predicate, call handler, abort on violation
  • -DHPX_CONTRACTS_MODE=1 → OBSERVE: check predicate, call handler, continue
  • -DHPX_CONTRACTS_MODE=2 → IGNORE: predicate never evaluated (zero cost)

These map directly to P2900's three semantics. In IGNORE mode HPX_CONTRACT_ASSERT(expr) compiles to ((void)0) - zero overhead.

The violation handler is user-installable (same API as hpx::assertion::set_assertion_handler), which makes it testable - instead of aborting, tests install a recording handler that captures violations and check them.


Build it yourself

cd poc/contracts
cmake -S . -B build && cmake --build build -j$(nproc)
./build/contracts_poc_enforce   # 20 passed
./build/contracts_poc_observe   # 20 passed
./build/contracts_poc_ignore    # 1 passed (verifies zero violations in ignore mode)

What this isn't

This is not the actual implementation. Specifically:

  • The violation handler here is header-only. In the real module it would be a compiled .cpp under libs/core/contracts/src/ with HPX_CORE_EXPORT linkage.
  • The macros here don't touch HPX_ASSERT at all. The real integration (via HPX_CONTRACTS_WITH_ASSERTS_AS_CONTRACT_ASSERTS) is already in the existing contracts module.
  • The optional<T> here is a standalone toy. The actual annotation is already on the feat/contracts-optional-operator-star branch in the real optional.hpp.
  • No CMake integration into HPX's build system - this builds standalone on purpose so reviewers can run it without a full HPX build.

Questions for reviewers

  1. The violation handler is noexcept throughout (matching the existing handle_assert). Is that right for observe mode too, or should we allow the handler to throw in observe mode to integrate with HPX's exception-based error propagation?

  2. For HPX_PRE / HPX_POST in fallback mode - I currently put them as body statements (top of function / before return). When native contracts land, they move to the declaration. Does HPX want a migration story for that, or is it acceptable that fallback-mode and native-mode HPX_PRE are syntactically in different positions?

  3. Is the priority order right - containers first, then futures, then parallel algorithms? Or should futures come first since future::get() on an invalid future is probably the most common real-world bug?

@StellarBot
Copy link
Copy Markdown

Can one of the admins verify this patch?

Copy link
Copy Markdown
Contributor

@hkaiser hkaiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you plan to integrate this proof of concept implementation with the existing infrastructure in HPX?

@hkaiser
Copy link
Copy Markdown
Contributor

hkaiser commented Apr 11, 2026

@Sanchit2662 What's your plans with moving this forward?

@Sanchit2662
Copy link
Copy Markdown
Contributor Author

Hey @hkaiser , thanks for taking a look!

Yeah so the plan is definitely not to keep this as a separate standalone thing. The idea is to integrate it properly with the existing assertion infrastructure in HPX. What I'm thinking is that HPX_PRE / HPX_POST / HPX_CONTRACT_ASSERT would just delegate to hpx::assertion::detail::handle_assert under the hood, or something very close to it. That way there's no duplication of the handler registration pattern that's already in libs/core/assertion/.

The three modes map pretty naturally to what HPX already does. IGNORE is basically how release builds work today where HPX_ASSERT expands to nothing. ENFORCE is the HPX_DEBUG equivalent. OBSERVE is the only genuinely new thing, it's the "log the violation but don't abort" mode, which the current assertion infra doesn't support.

For what to annotate first, I was thinking of following the same priority P3471 uses for the hardened STL. So hpx::optional first since it's a direct equivalent (operator*, operator->, value() all need has_value() to be true). Then HPX containers for out-of-bounds stuff, then hpx::future / hpx::shared_future since get() has a clear valid() precondition, and then parallel algorithms for iterator range checks.

On the macro side, the design I have in mind keeps a clean migration path. When a C++26 compiler with native contract support shows up, HPX_PRE / HPX_POST can just expand to the native pre / post syntax without needing to re-annotate everything.

One thing I'm genuinely unsure about though: should the contract mode be its own CMake option like HPX_WITH_CONTRACTS_MODE that exists alongside HPX_DEBUG, or is it cleaner to just fold it into the existing debug flag for now? Would love your thoughts on that.

@hkaiser
Copy link
Copy Markdown
Contributor

hkaiser commented Apr 12, 2026

Yeah so the plan is definitely not to keep this as a separate standalone thing. The idea is to integrate it properly with the existing assertion infrastructure in HPX. What I'm thinking is that HPX_PRE / HPX_POST / HPX_CONTRACT_ASSERT would just delegate to hpx::assertion::detail::handle_assert under the hood, or something very close to it. That way there's no duplication of the handler registration pattern that's already in libs/core/assertion/.

The three modes map pretty naturally to what HPX already does. IGNORE is basically how release builds work today where HPX_ASSERT expands to nothing. ENFORCE is the HPX_DEBUG equivalent. OBSERVE is the only genuinely new thing, it's the "log the violation but don't abort" mode, which the current assertion infra doesn't support.

IIUC, you suggest adding an additional mode to the existing infrastructure that logs violations. That would be ok, I think.

For what to annotate first, I was thinking of following the same priority P3471 uses for the hardened STL. So hpx::optional first since it's a direct equivalent (operator*, operator->, value() all need has_value() to be true). Then HPX containers for out-of-bounds stuff, then hpx::future / hpx::shared_future since get() has a clear valid() precondition, and then parallel algorithms for iterator range checks.

As said, modifying hpx::optional does not make real sense as this is a fall back workaround version used for older compilers only. Except for that, hpx::optional is simply a alias for std::optional.

One thing I'm genuinely unsure about though: should the contract mode be its own CMake option like HPX_WITH_CONTRACTS_MODE that exists alongside HPX_DEBUG, or is it cleaner to just fold it into the existing debug flag for now? Would love your thoughts on that.

For pre-C++26 compilers this has to be a HPX CMake option. For conforming compilers this can be derived from the compiler options themselves.

@codacy-production
Copy link
Copy Markdown

codacy-production bot commented Apr 12, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
Duplication 0

View in Codacy

TIP This summary will be updated as you push new changes. Give us feedback

@Sanchit2662
Copy link
Copy Markdown
Contributor Author

Hey @hkaiser , thanks for the correction on hpx::optional, I didn't realize it was just an alias for std::optional on modern compilers so yeah annotating it doesn't really make sense.
I'm thinking hpx::future::get() is a better first target since the valid() precondition is clear and something people actually get wrong. Then containers and parallel algorithms after that.
On the CMake side, HPX_WITH_CONTRACTS_MODE for pre-C++26 and deriving it from compiler flags for conforming compilers makes sense to me.
One thing I'm unsure about: for adding the OBSERVE mode, should it go directly into libs/core/assertion/ or would you prefer it stay separate for now?

Also noticed the Codacy flags, looking into those now.

@hkaiser
Copy link
Copy Markdown
Contributor

hkaiser commented Apr 14, 2026

One thing I'm unsure about: for adding the OBSERVE mode, should it go directly into libs/core/assertion/ or would you prefer it stay separate for now?

If it is possible to have it separate, leave it separate. If this results in too much code duplication (or other issues), let's integrate it with the assertion module. The current contracts support lives in its own HPX module, maybe we should try to have everything related there.

@Sanchit2662
Copy link
Copy Markdown
Contributor Author

Hey @hkaiser , quick update on how I'm planning to move this forward so you have the full picture.

First thing, I'll delete the whole poc/contracts/ directory from this branch. All of it, including the README. That code was just to validate the design, it doesn't need to live in the repo.
Then the actual work goes into the existing libs/core/contracts/ module. The plan is:

  1. Port the violation handler (the violation_info struct, set_violation_handler, default handler, etc.) into the module as a proper header plus source file. I'll use hpx::source_location instead of std::source_location since HPX already has its own.

  2. Add a HPX_WITH_CONTRACTS_MODE CMake option with ENFORCE / OBSERVE / IGNORE. Then rewrite macros.hpp so that when native C++26 contracts aren't available, the macros dispatch based on that mode. OBSERVE is the new behavior (log and continue), ENFORCE aborts, IGNORE is the current no-op fallback.

  3. Port the PoC tests into libs/core/contracts/tests/unit/ as proper HPX module tests, one test file per case.

  4. Pick hpx::future::get() as the first real annotation target since valid() is a clean precondition. Get that working end-to-end across all three modes with regression tests before I touch anything else. This is the step that proves the whole thing actually works.

  5. Once that's solid, scale up to the HPX containers, then parallel algorithms, following P3471's priorities.

Planning to split this across separate commits so each piece is reviewable on its own instead of one giant diff. Let me know if any of this feels off before I start.

Also looking into the Codacy flags, most of them are on the PoC files which will be gone anyway, but I'll go through them properly.

Copy link
Copy Markdown
Contributor

@hkaiser hkaiser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please force push to completely remove the poc subdirectory from the git history.

Comment on lines +1 to +3
// Copyright (c) 2025 The STE||AR-Group
// Copyright (c) 2025 Alexandros Papadakis
// Copyright (c) 2026 The STE||AR-Group
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to update the copyright for the STE||AR-Group (why would you, BTW), please consolidate the lines:

Suggested change
// Copyright (c) 2025 The STE||AR-Group
// Copyright (c) 2025 Alexandros Papadakis
// Copyright (c) 2026 The STE||AR-Group
// Copyright (c) 2025-2026 The STE||AR-Group
// Copyright (c) 2025 Alexandros Papadakis

Comment on lines +31 to +36
HPX_CORE_EXPORT void set_violation_handler(
violation_handler_t handler) noexcept;
HPX_CORE_EXPORT violation_handler_t get_violation_handler() noexcept;

HPX_CORE_EXPORT void default_violation_handler(violation_info const& info);
HPX_CORE_EXPORT void invoke_violation_handler(violation_info const& info);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most likely these functions should be marrked with export if C++ modules are enabled:

Suggested change
HPX_CORE_EXPORT void set_violation_handler(
violation_handler_t handler) noexcept;
HPX_CORE_EXPORT violation_handler_t get_violation_handler() noexcept;
HPX_CORE_EXPORT void default_violation_handler(violation_info const& info);
HPX_CORE_EXPORT void invoke_violation_handler(violation_info const& info);
HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT void set_violation_handler(
violation_handler_t handler) noexcept;
HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT
violation_handler_t get_violation_handler() noexcept;
HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT
void default_violation_handler(violation_info const& info);
HPX_CXX_CORE_EXPORT HPX_CORE_EXPORT
void invoke_violation_handler(violation_info const& info);


namespace hpx::contracts {

enum class contract_kind
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The defined data types most likely need annotations for C++ modules:

Suggested change
enum class contract_kind
HPX_CXX_CORE_EXPORT enum class contract_kind

same is true for the struct violation_info below.

Comment thread libs/core/contracts/CMakeLists.txt Outdated
# Contract evaluation mode for pre-C++26 compilers. Not registered via
# hpx_option(MODULE CONTRACTS) to avoid triggering the config_entries.cpp
# generation mechanism before add_hpx_module creates the build directory.
set(HPX_WITH_CONTRACTS_MODE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use hpx_option here:

hpx_option(
  HPX_WITH_CONTRACTS_MODE
  STRING
  "Contract evaluation mode for pre-C++26 compilers, options are: ENFORCE, OBSERVE, IGNORE"
  "ENFORCE"
  STRINGS "ENFORCE;OBSERVE;IGNORE"
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, should we make ENFORCE the default in Debug mode only?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea. How should we handle multi-config generators though, where CMAKE_BUILD_TYPE is empty at configure time? Is there a preferred pattern for this in HPX already?

Comment thread libs/core/contracts/CMakeLists.txt Outdated

if(HPX_WITH_CONTRACTS_MODE STREQUAL "ENFORCE")
hpx_add_config_define_namespace(
DEFINE HPX_CONTRACTS_MODE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use HPX_HAVE_xxx as the preprocessor macro for a corresponding HPX_WITH_xxx CMake option.

};

HPX_CXX_CORE_EXPORT using violation_handler_t =
void (*)(violation_info const&);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better if this was accepting any callable of the given signature:

Suggested change
void (*)(violation_info const&);
hpx::unique_function<void(violation_info const&)>

?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just to confirm , when you said hpx::unique_function , did you mean hpx::move_only_function? That's what I found in the codebase. Also switching from a raw function pointer to a move-only wrapper would change the internal storage in violation_handler.cpp ; since we can't hold it in a plain static pointer anymore.
Makes sense to me if that's the direction, just wanted to confirm before changing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant move_only_function, sorry for the confusion.

HPX_CXX_CORE_EXPORT using violation_handler_t =
void (*)(violation_info const&);

HPX_CORE_EXPORT void set_violation_handler(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should return the previously registered violation handler to allow chaining several handlers, if needed.

// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <hpx/contracts/config/defines.hpp>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may need to #include<hpx/config.hpp>

Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
@Sanchit2662 Sanchit2662 force-pushed the poc/contracts-infrastructure branch from e2595a6 to 7dfefd1 Compare April 18, 2026 20:52
Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
@Sanchit2662
Copy link
Copy Markdown
Contributor Author

Sanchit2662 commented Apr 18, 2026

so i've addressed the review feedback.
on the implementation side, the violation handler infrastructure is in place, the ENFORCE/OBSERVE/IGNORE mode dispatch is wired up in macros.hpp, and the test suite has been ported into the module. next up is the first real annotation on hpx::future::get(), and after that scaling up to containers and parallel algorithms. also will look into the CI failures.

hpx_add_config_define_namespace treats a numeric "0" argument as falsy
and emits a valueless #define, which caused the #if HPX_HAVE_CONTRACTS_MODE
preprocessor check to fail with a syntax error on every build job. Shift
the mode encoding to 1/2/3 (ENFORCE/OBSERVE/IGNORE) and guard the checks
with defined() so the macro is robust to the emit path.

Also update the fallback test WILL_FAIL expectations: HPX_CONTRACT_ASSERT
now routes through the violation handler in every build config, so tests
that hit it must WILL_FAIL unconditionally under ENFORCE (the default),
not only in Debug.
…itions

  Adds HPX_PRE(this->valid()) to both get() overloads as the first real
  end-to-end use of the contracts infrastructure. Under native C++26 the
  compiler enforces the pre-condition; in fallback mode HPX_PRE is a no-op
  and the existing no_state throw continues to handle invalid futures.

  Also fold in clang-format and cmake-format fixes flagged by CI on the
  previous commit.

Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
  enforced pre-conditions; under fallback they are no-ops, matching the
  design of HPX_PRE as a declaration specifier.

Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
@Sanchit2662 Sanchit2662 requested a review from hkaiser April 19, 2026 11:54
@Sanchit2662
Copy link
Copy Markdown
Contributor Author

While scaling up the annotations I ran into a design question I'd like your input on before I go much further.

Right now HPX_PRE and HPX_POST are pure no-ops in fallback mode, regardless of HPX_WITH_CONTRACTS_MODE. The reasoning is in the macros.hpp comment: they're declaration specifiers in C++26 (int f(int x) pre(x > 0);), so they can't be faithfully replicated as statement macros without moving the check into every call site.

The consequence is that an annotation like HPX_PRE(this->valid()) on future::get() only does anything under a C++26-with-contracts compiler. In every other build ,which is every CI config today it's documentation only. That makes the ENFORCE/OBSERVE/IGNORE modes effectively useless for HPX_PRE/HPX_POST; they only affect HPX_CONTRACT_ASSERT.

Two ways I can see to resolve this:

  1. Accept it. Contracts are framed as a C++26-forward feature. Fallback preserves syntax so code compiles on today's toolchains but doesn't check at runtime. Annotations are then mostly about documenting intent and readying the codebase for C++26.

  2. Introduce a parallel HPX_PRECONDITION(x) / HPX_POSTCONDITION(x) as statement macros used inside function bodies. These would dispatch on HPX_WITH_CONTRACTS_MODE in fallback (same as HPX_CONTRACT_ASSERT), giving ENFORCE/OBSERVE something to enforce today. The tradeoff is two parallel APIs and annotations placed in the body rather than at the signature.

My lean is (1) for simplicity, but (2) is more useful in the near term. Which way would you like to go?

@hkaiser
Copy link
Copy Markdown
Contributor

hkaiser commented Apr 19, 2026

While scaling up the annotations I ran into a design question I'd like your input on before I go much further.

Right now HPX_PRE and HPX_POST are pure no-ops in fallback mode, regardless of HPX_WITH_CONTRACTS_MODE. The reasoning is in the macros.hpp comment: they're declaration specifiers in C++26 (int f(int x) pre(x > 0);), so they can't be faithfully replicated as statement macros without moving the check into every call site.

The consequence is that an annotation like HPX_PRE(this->valid()) on future::get() only does anything under a C++26-with-contracts compiler. In every other build ,which is every CI config today it's documentation only. That makes the ENFORCE/OBSERVE/IGNORE modes effectively useless for HPX_PRE/HPX_POST; they only affect HPX_CONTRACT_ASSERT.

Two ways I can see to resolve this:

  1. Accept it. Contracts are framed as a C++26-forward feature. Fallback preserves syntax so code compiles on today's toolchains but doesn't check at runtime. Annotations are then mostly about documenting intent and readying the codebase for C++26.
  2. Introduce a parallel HPX_PRECONDITION(x) / HPX_POSTCONDITION(x) as statement macros used inside function bodies. These would dispatch on HPX_WITH_CONTRACTS_MODE in fallback (same as HPX_CONTRACT_ASSERT), giving ENFORCE/OBSERVE something to enforce today. The tradeoff is two parallel APIs and annotations placed in the body rather than at the signature.

My lean is (1) for simplicity, but (2) is more useful in the near term. Which way would you like to go?

That's a tough call. However, (1) is preferred as it avoids code duplication. We should combine that with a CI that actually supports contracts (similar to what we have added for the C++ reflection capabilities).

It might be worth thinking about whether we can find expansions for HPX_PRE/HPX_POST that result in valid pre-C++26 code but still allow for injecting checks. After all HPX_PRE is placed where a requires clause and HPX_POST goes where trailing return types would go... I'm not sure if this, but let's play with potential solutions.

@hkaiser
Copy link
Copy Markdown
Contributor

hkaiser commented Apr 19, 2026

It might be worth thinking about whether we can find expansions for HPX_PRE/HPX_POST that result in valid pre-C++26 code but still allow for injecting checks. After all HPX_PRE is placed where a requires clause and HPX_POST goes where trailing return types would go... I'm not sure if this, but let's play with potential solutions.

Answering my own comment: this is probably not possible as both, the requires clause and the traing return type can be used for compile-time checks only...

@Sanchit2662
Copy link
Copy Markdown
Contributor Author

Hey @hkaiser , glad we're aligned on option (1) , that keeps things clean and avoids a parallel API that we'd eventually have to maintain.
I looked into the CI side and I think the contracts job would be pretty straightforward to add. The structure is almost identical to what we already have for the GCC trunk reflection job , same YAML shape, just swap -freflection for -fcontracts, add -DHPX_WITH_CONTRACTS=ON, and point the build and test targets at tests.unit.modules.contracts. The feature probe in
cmake/tests/cxx26_contracts.cpp already handles auto-detecting __cpp_contracts and setting HPX_HAVE_CXX26_CONTRACTS, so no CMake changes would be needed on top of that.

Before I go ahead and write the workflow file though, I had a few questions I wanted to check with you:

First, do you know if we can reuse the existing gcc_trunk_build_env:1 image? Since GCC 15 already has -fcontracts support, if that image was built against GCC 15 or newer, we might not need a new image at all , just a new YAML file pointing at the same container. That'd be the simplest path.

If a fresh image is needed (something like gcc_contracts_build_env:1), I'm happy to put together a Dockerfile for it , but I'd need someone with access to the stellargroup Docker Hub to actually build and push it. Is that something you'd handle, or is there a process I should follow for that?

And lastly, any preference on whether we go GCC-only for now, or also add a Clang variant? The Clang contracts implementation is still pretty experimental upstream, so GCC-only feels like the safer starting point to me , but happy to go either way if you have a preference.
Once I have clarity on the image question I can have the workflow file ready to go quickly!

…ctor with preconditions

Add HPX_PRE(first <= last) to hpx::sort and hpx::stable_sort (both
sequential and parallel overloads). Both algorithms already enforce
std::random_access_iterator via static_assert, so <= is always valid.

Add HPX_PRE(pos < size()) to partitioned_vector::operator[] (const and
non-const). Mirrors the existing small_vector annotation.

Signed-off-by: Sanchit2662 <sanchit2662@gmail.com>
@Sanchit2662 Sanchit2662 force-pushed the poc/contracts-infrastructure branch from 135db57 to 50e9ea1 Compare April 21, 2026 12:28
@hkaiser
Copy link
Copy Markdown
Contributor

hkaiser commented Apr 21, 2026

Just as a FYI: https://wg21.link/p4044

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants