-
Notifications
You must be signed in to change notification settings - Fork 14
Comparing changes
Open a pull request
base repository: ngcpp/proxy
base: main
head repository: ngcpp/proxy
compare: feature/v5
- 17 commits
- 62 files changed
- 1 contributor
Commits on Jul 22, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 7f847ed - Browse repository at this point
Copy the full SHA 7f847edView commit details -
Configuration menu - View commit details
-
Copy full SHA for d63b436 - Browse repository at this point
Copy the full SHA d63b436View commit details
Commits on Jul 24, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 4b49a1a - Browse repository at this point
Copy the full SHA 4b49a1aView commit details
Commits on Aug 28, 2026
-
Refactor lifetime model selection into type traits (#69)
Replace the `*_impl` proxy creation functions with type traits that name the selected lifetime model, so that the models can be reused by types other than `proxy` (e.g. an upcoming `box`). No observable behavior change. - Rename the internal `allocated_ptr` class template to `wide_ptr`, and add `allocated_ptr`, `owned_ptr` and `shared_ptr` type traits that select a lifetime model instead of constructing a `proxy` directly. The creation functions now construct `proxy<F>` from the selected pointer type. - Let `inplace_ptr` ignore its first constructor argument so that all owning lifetime models share a uniform `(alloc, args...)` construction signature. - Order the `T&& value` overload first in each creation function family, and renumber the corresponding specs to match.
Configuration menu - View commit details
-
Copy full SHA for b76fd39 - Browse repository at this point
Copy the full SHA b76fd39View commit details
Commits on Aug 30, 2026
-
Introduce the ProBasicMeta and ProMeta named requirements (#66)
A "meta" is an object holding metadata deduced from a type at compile time, stored in or referenced by a proxy. proxy creates, copies, assigns, and destroys metadata in contexts specified not to throw, but nothing required a reflector to actually support those operations without throwing, or to be default-constructible at all. Define the ProBasicMeta and ProMeta named requirements, and enforce them via the new basic_meta, meta, and basic_reflection concepts. is_reflector_well_formed() now checks meta<R, T> rather than plain constructibility, so a reflector that can throw, or that cannot be default-constructed, copied, or assigned, is no longer proxiable and is diagnosed as a reflection that is not implemented. This tightens proxiable: a reflector whose constructor may throw was previously accepted.
Configuration menu - View commit details
-
Copy full SHA for 7f5cb7b - Browse repository at this point
Copy the full SHA 7f5cb7bView commit details -
Give each convention a single overload type (#67)
A convention used to carry a tuple-like overload_types, so adding a convention had to search Cs for an existing convention with the same is_direct and dispatch_type and merge the overload lists into it. That merge is the only reason add_conv_t, merge_conv_t, add_conv_reduction, and conv_specialization_t exist. Replace overload_types with a single overload_type, so add_convention contributes one convention per overload and merging a convention into Cs becomes deduplicating concatenation. Duplicates are still collapsed, so build() is unaffected at both compile time and run time. Accessors still have to be formed per dispatch type, or a dispatch with several overloads would contribute several accessor bases instead of one overload set. Regroup the conventions by dispatch type via conv_group and conv_groups_merge_t just before generating the accessors, which also keeps overload shadowing working. Generalize the reduction helpers to carry extra arguments (reduction_t) and add flattening_merge_t, which merge_tuples_t and conv_groups_merge_t are both expressed in terms of. This changes the ProBasicConvention and ProConvention requirements, so a hand-written convention type must be updated.
Configuration menu - View commit details
-
Copy full SHA for 96e00f2 - Browse repository at this point
Copy the full SHA 96e00f2View commit details
Commits on Aug 31, 2026
-
Invoke through an erased context instead of the proxy type (#68)
An invoker's erased function pointer was typed R (*)(proxy<F>&, D, Args...), so its type named the facade it was built for. That is fine while metadata is only ever read by a proxy of exactly that facade, but it prevents one proxy from reusing another's invoker: two proxy types have different layouts, so passing one where the other is expected is not valid. Introduce erased_context, which carries only a pointer to the storage of the contained value, and type invokers as invoker<Ctx, O>. Invocation now resolves the contained type inside the context rather than through reinterpret_invoke, and the lifetime dispatches take a void* rather than a target proxy, so their invokers no longer mention F either. Resetting the source metadata after an rvalue-qualified call moves to the call site, where the facade is known. Declare ptr_ ahead of meta_ so that the storage of the contained value lies at offset 0. Every invocation now builds a context from it, and at offset 0 that context is the address of the proxy itself. Where a proxy is invoked more than once, the caller then keeps a single value live instead of a separate context pointer: on aarch64 that removes a spill and reload of the context across the first call, and shrinks the frame by 16 bytes. Neither sizeof(proxy) nor its alignment changes. relocate_dispatch becomes a tag with its own erased_context specialization, which absorbs the bitwise-relocation path that used to be selected via internal_dispatch, and internal_dispatch is removed. substitution_dispatch needs the same path, because it relocates a bitwise-relocatable value without requiring it to be move-constructible, so it gets a specialization too; both it and the specialization drop out once `super` replaces substitution. Removes the public reinterpret_invoke, which had no remaining use: the invoker macro was its only caller inside the library.
Configuration menu - View commit details
-
Copy full SHA for ec7e7de - Browse repository at this point
Copy the full SHA ec7e7deView commit details -
Configuration menu - View commit details
-
Copy full SHA for ca59fe2 - Browse repository at this point
Copy the full SHA ca59fe2View commit details
Commits on Sep 1, 2026
-
Reach metadata by conversion instead of by named lookup (#71)
meta_storage looked a meta up with get<M>(), which resolved to a static_cast over a flat set of base classes. That works only while every meta is a direct base of the storage, and cannot reach a meta held inside an aggregate. Replace it with proxy_meta, whose contained metas are reached through a conversion operator. A meta is contained if the metadata converts to it without throwing, so an aggregate that itself converts to a meta makes that meta reachable too. unique_types_t reduces the meta list so that each entry is contained by exactly one entry, namely itself, which is the property that keeps the conversion unambiguous: a duplicate collapses onto its leftmost occurrence, and a meta subsumed by an aggregate is replaced by that aggregate in place. Both storages now expose the metadata through operator*, so choosing between them is independent of how a meta is looked up. static_meta_storage holds a single meta and is chosen by size rather than by shape, which separates the metadata layout from the decision to hold it out of line. Under pointer authentication, assigning one storage from another signs a raw pointer, which meta_ptr now supports. No functional change.
Configuration menu - View commit details
-
Copy full SHA for 07e6520 - Browse repository at this point
Copy the full SHA 07e6520View commit details
Commits on Sep 9, 2026
-
Reset the proxy when the destructor of the underlying pointer throws (#…
…82) * Reset the proxy when the destructor of the underlying pointer throws proxy::destroy() invoked destruction through an lvalue-qualified overload, so the meta_resetting_guard that invoke_impl applies to consuming overloads never ran. When the destructor of the underlying pointer threw, the metadata still pointed at the destroyed object, so has_value() stayed true and the next destruction ran on a dead object. Every path that discards a value reached this: reset(), operator=(nullptr), both branches of the copy assignment operator, the move assignment operator, operator=(P&&) and both emplace overloads. Destruction is a consuming operation like relocation, so give it the same shape. The destroy meta now uses an rvalue-qualified overload, which makes erased_context destroy the pointer through destroying_guard and makes invoke_impl clear the metadata on both the normal and the exceptional path. destroy_dispatch keeps only its tag role and its call operator becomes a no-op, because the destruction it used to perform is what the rvalue machinery already does. The added reset is dead on the non-throwing path and the optimizer removes it. At -O2 the disassembly of ~proxy, reset and the move assignment operator is unchanged for a facade whose destructibility is nothrow. LifetimeTracker gains ThrowingDestructionSession, a Session whose destructor throws, which is the first pointer in the suite with a potentially throwing destructor and the first use of a facade whose destructibility is nontrivial. * Fix MSVC failure
Configuration menu - View commit details
-
Copy full SHA for 7c4e174 - Browse repository at this point
Copy the full SHA 7c4e174View commit details -
Configuration menu - View commit details
-
Copy full SHA for e2bae00 - Browse repository at this point
Copy the full SHA e2bae00View commit details -
Refuse a mutable proxy_cast on a const contained value (#80)
proxy_cast_dispatch guarded a reference result with std::is_const_v<T>, where T is the deduced operand type and is therefore always a reference. A reference type is never const, so the guard never fired and a caller could ask a const proxy for a mutable reference to what it contains and get one, silently casting the constness away. The guard now tests the referenced type. proxy_cast<int&> on a proxy whose contained value is const throws bad_proxy_cast, and the pointer form returns nullptr, which is what the const-qualified overload already promised. Reaching a const contained value still works by asking for it as const.
Configuration menu - View commit details
-
Copy full SHA for b5ea4a9 - Browse repository at this point
Copy the full SHA b5ea4a9View commit details
Commits on Sep 10, 2026
-
Configuration menu - View commit details
-
Copy full SHA for f65a24c - Browse repository at this point
Copy the full SHA f65a24cView commit details -
Configuration menu - View commit details
-
Copy full SHA for a9f488f - Browse repository at this point
Copy the full SHA a9f488fView commit details
Commits on Sep 11, 2026
-
[super! 5/6] Add super facades (#74)
* Add super facades add_facade<F> copied F's conventions and reflections into the built facade. The two facades then shared behavior but had unrelated metadata, so converting a proxy of one to a proxy of the other needed an explicit substitution convention and an indirect call to translate. Give a facade a super_types list. add_facade<F> records F there instead of copying, and the metadata of the built facade embeds the metadata of each super, so const proxy_meta<Derived>& converts to const proxy_meta<Super>&. proxy gains converting constructors and assignment operators guarded on exactly that conversion: the metadata is carried over directly, and only the contained value is copied or relocated. A convention whose overload is a facade_aware_overload_t is the exception to "not copied": its overload depends on the facade it is built into, so it is also checked and made available against the built facade. That is what lets as_view declared on a super yield a proxy_view of the built facade rather than of the super. Accessors are formed from the conventions of the facade and of every super, regrouped per dispatch type, so an overload set spanning a super and the facade that derives from it stays a single overload set. observer_facade and weak_facade map super_types through themselves, so view-ness and weak-ness are preserved across a conversion to a super. add_facade<F, true>, deprecated since 4.1.0, is removed. The second parameter of add_facade, deprecated since 4.1.0, is retained and ignored: a proxy of the built facade already converts to a proxy<F> because F is a super. add_facade_with_substitution and substitution_dispatch are unchanged and still take precedence where both apply; they are addressed in a follow-up. * Reach the trivial copy and relocation by the source facade A converting initialization asked the destination facade whether the copy or the relocation is trivial, but the triviality that licenses a byte copy belongs to the value being moved, which lives in the source. A super is never stricter than the facade converting to it, so the byte copy was missed whenever the derived facade was the stricter of the two, and the value went through the erased invoker instead. Corrected three lines of the specification along the way. The copy assignment is not "as if by auto(rhs).swap(*this)", which is not even formed for a facade that forbids relocation. The converting move assignment loses the contained value on a throwing relocation exactly as the move assignment does. The move constructor is noexcept for trivial relocatability, which its documented signature spelled as an equality.
Configuration menu - View commit details
-
Copy full SHA for 28e938e - Browse repository at this point
Copy the full SHA 28e938eView commit details
Commits on Sep 13, 2026
-
Support assignment and swap for a facade that forbids relocation (#77)
* Fix assignment for a facade that forbids relocation proxy::operator=(const proxy&) commits a throwing copy through a temporary, which needs a move assignment. A facade that forbids relocation has none, so the expression re-selected the copy assignment itself and recursed until the stack overflowed. proxy::operator=(P&&) reaches the same expression and inherited the crash, and failed to compile outright for a facade that is not copyable either. Stage the temporary only where an assignment exists to commit it with, and destroy the contained value before constructing the new one otherwise. Assignment then works for every facade, at the cost of leaving *this without a value when the construction throws, which is the best a facade that can neither relocate nor copy without throwing can offer. Take the staged form whenever the commit cannot throw, which is copyability >= nothrow as much as relocatability >= nontrivial. A facade with nothrow copyability keeps its old value when the construction throws, as one with a trivial copy assignment already did. * Exchange values by copying when a facade forbids relocation proxy::swap relocates, so a facade that forbids relocation had no swap at all unless it was trivially copyable, even though std::swap already exchanged such proxies through the copy constructor and the copy assignment, both of which bind an rvalue. The member was missing for types the standard library already reports as swappable. Add an overload for exactly those facades, constrained on relocatability == none, that exchanges the values by copying. Splitting it from the relocating overload rather than branching inside one keeps both noexcept specifications honest: the relocating overload is untouched, and the new one is noexcept when the copies and the destructions are. An empty operand is exchanged with a single copy rather than through a temporary. A facade that can relocate keeps relocating, even where the relocation can throw and a copy could not. Exchanging by copy is what a facade with no other way gets, not a path taken from one that has one. Documented the constraint the hidden friend has always carried.
Configuration menu - View commit details
-
Copy full SHA for 94a64f1 - Browse repository at this point
Copy the full SHA 94a64f1View commit details -
Reduce direct RTTI to a single reflection (#81)
direct_rtti added three conventions to carry proxy_cast, so every proxiable pointer paid three function pointers of metadata and every cast went through one of them. The typeid reflection that the same skill installs already records the contained type, and once that type is known to match the requested one the cast is a static_cast on the pointer storage, so the indirection buys nothing. direct_rtti now adds one reflection. direct_rtti_reflector inherits proxy_typeid_reflector for the type identity and reuses the accessor generated for proxy_cast_dispatch, so the five proxy_cast overloads and their qualifier mapping stay in one place. proxy_cast_accessor_impl gained a private invoke_cast that tests the reflected type and then invokes the same dispatch through an erased context with the contained type known statically. The indirect path keeps its conventions and compiles to the same code as before. The metadata of a facade built from direct_rtti alone drops from 40 bytes to 16, and the lvalue, pointer and rvalue casts compile to 27, 29 and 34 instructions in place of 46, 37 and 66. No indirect call is left on the success path. The rvalue form keeps one on the type mismatch branch, where the proxy is reset through the erased destructor.
Configuration menu - View commit details
-
Copy full SHA for 5aced7c - Browse repository at this point
Copy the full SHA 5aced7cView commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...feature/v5