Skip to content

Commit

Permalink
refactor: Extract unsafe_new_with_self
Browse files Browse the repository at this point in the history
roberth committed Nov 24, 2024

Verified

This commit was signed with the committer’s verified signature.
rouault Even Rouault
1 parent 1bd7517 commit f06f611
Showing 1 changed file with 42 additions and 27 deletions.
69 changes: 42 additions & 27 deletions src/libexpr-c/nix_api_expr.cc
Original file line number Diff line number Diff line change
@@ -19,6 +19,29 @@
# include <mutex>
#endif

/**
* @brief Allocate and initialize using self-reference
*
* This allows a brace initializer to reference the object being constructed.
*
* @warning Use with care, as the pointer points to an object that is not fully constructed yet.
*
* @tparam T Type to allocate
* @tparam F A function type for `init`, taking a T* and returning the initializer for T
* @param init Function that takes a T* and returns the initializer for T
* @return Pointer to allocated and initialized object
*/
template <typename T, typename F>
static T * unsafe_new_with_self(F && init)
{
// Allocate
void * p = ::operator new(
sizeof(T),
static_cast<std::align_val_t>(alignof(T)));
// Initialize with placement new
return new (p) T(init(static_cast<T *>(p)));
}

nix_err nix_libexpr_init(nix_c_context * context)
{
if (context)
@@ -99,18 +122,14 @@ nix_eval_state_builder * nix_eval_state_builder_new(nix_c_context * context, Sto
if (context)
context->last_err_code = NIX_OK;
try {
// Allocate ahead of time, because .settings needs self-reference
void * p = ::operator new(
sizeof(nix_eval_state_builder),
static_cast<std::align_val_t>(alignof(nix_eval_state_builder)));
auto * p2 = static_cast<nix_eval_state_builder *>(p);
new (p) nix_eval_state_builder{
.store = nix::ref<nix::Store>(store->ptr),
.settings = nix::EvalSettings{/* &bool */ p2->readOnlyMode},
.fetchSettings = nix::fetchers::Settings{},
.readOnlyMode = true,
};
return p2;
return unsafe_new_with_self<nix_eval_state_builder>([&](auto * self) {
return nix_eval_state_builder{
.store = nix::ref<nix::Store>(store->ptr),
.settings = nix::EvalSettings{/* &bool */ self->readOnlyMode},
.fetchSettings = nix::fetchers::Settings{},
.readOnlyMode = true,
};
});
}
NIXC_CATCH_ERRS_NULL
}
@@ -152,21 +171,17 @@ EvalState * nix_eval_state_build(nix_c_context * context, nix_eval_state_builder
if (context)
context->last_err_code = NIX_OK;
try {
// Allocate ahead of time, because .state init needs self-reference
void * p = ::operator new(
sizeof(EvalState),
static_cast<std::align_val_t>(alignof(EvalState)));
auto * p2 = static_cast<EvalState *>(p);
new (p) EvalState {
.fetchSettings = std::move(builder->fetchSettings),
.settings = std::move(builder->settings),
.state = nix::EvalState(
builder->lookupPath,
builder->store,
p2->fetchSettings,
p2->settings),
};
return p2;
return unsafe_new_with_self<EvalState>([&](auto * self) {
return EvalState{
.fetchSettings = std::move(builder->fetchSettings),
.settings = std::move(builder->settings),
.state = nix::EvalState(
builder->lookupPath,
builder->store,
self->fetchSettings,
self->settings),
};
});
}
NIXC_CATCH_ERRS_NULL
}

0 comments on commit f06f611

Please sign in to comment.