1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 19:01:16 +02:00

refactor: Extract unsafe_new_with_self

This commit is contained in:
Robert Hensing 2024-11-22 17:26:26 +01:00
parent 1bd7517801
commit f06f611ff3

View file

@ -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
}