Commit f861809b authored by Kenton Varda's avatar Kenton Varda

Add functions for attaching context to a bare value or reference.

This is a lot like Own<T>::attach() but for the case where you don't have a Own pointer, you just have a reference or value that you want to attach stuff to.
parent c9b92630
......@@ -136,6 +136,68 @@ TEST(Memory, AttachNested) {
KJ_EXPECT(destroyed3 == 3, destroyed3);
}
KJ_TEST("attachRef") {
uint counter = 0;
uint destroyed1 = 0;
uint destroyed2 = 0;
uint destroyed3 = 0;
auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
int i = 123;
Own<int> combined = attachRef(i, kj::mv(obj1), kj::mv(obj2), kj::mv(obj3));
KJ_EXPECT(combined.get() == &i);
KJ_EXPECT(obj1.get() == nullptr);
KJ_EXPECT(obj2.get() == nullptr);
KJ_EXPECT(obj3.get() == nullptr);
KJ_EXPECT(destroyed1 == 0);
KJ_EXPECT(destroyed2 == 0);
KJ_EXPECT(destroyed3 == 0);
combined = nullptr;
KJ_EXPECT(destroyed1 == 1, destroyed1);
KJ_EXPECT(destroyed2 == 2, destroyed2);
KJ_EXPECT(destroyed3 == 3, destroyed3);
}
KJ_TEST("attachVal") {
uint counter = 0;
uint destroyed1 = 0;
uint destroyed2 = 0;
uint destroyed3 = 0;
auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
int i = 123;
Own<int> combined = attachVal(i, kj::mv(obj1), kj::mv(obj2), kj::mv(obj3));
int* ptr = combined.get();
KJ_EXPECT(ptr != &i);
KJ_EXPECT(*ptr == i);
KJ_EXPECT(obj1.get() == nullptr);
KJ_EXPECT(obj2.get() == nullptr);
KJ_EXPECT(obj3.get() == nullptr);
KJ_EXPECT(destroyed1 == 0);
KJ_EXPECT(destroyed2 == 0);
KJ_EXPECT(destroyed3 == 0);
combined = nullptr;
KJ_EXPECT(destroyed1 == 1, destroyed1);
KJ_EXPECT(destroyed2 == 2, destroyed2);
KJ_EXPECT(destroyed3 == 3, destroyed3);
}
struct StaticType {
int i;
};
......
......@@ -426,6 +426,21 @@ Own<Decay<T>> heap(T&& orig) {
return Own<T2>(new T2(kj::fwd<T>(orig)), _::HeapDisposer<T2>::instance);
}
template <typename T, typename... Attachments>
Own<Decay<T>> attachVal(T&& value, Attachments&&... attachments);
// Returns an Own<T> that takes ownership of `value` and `attachments`, and points to `value`.
//
// This is equivalent to heap(value).attach(attachments), but only does one allocation rather than
// two.
template <typename T, typename... Attachments>
Own<T> attachRef(T& value, Attachments&&... attachments);
// Like attach() but `value` is not moved; the resulting Own<T> points to its existing location.
// This is preferred if `value` is already owned by one of `attachments`.
//
// This is equivalent to Own<T>(&value, kj::NullDisposer::instance).attach(attachments), but
// is easier to write and allocates slightly less memory.
// =======================================================================================
// SpaceFor<T> -- assists in manual allocation
......@@ -519,4 +534,17 @@ Own<T> Own<T>::attach(Attachments&&... attachments) {
return Own<T>(ptrCopy, *bundle);
}
template <typename T, typename... Attachments>
Own<T> attachRef(T& value, Attachments&&... attachments) {
auto bundle = new _::DisposableOwnedBundle<Attachments...>(kj::fwd<Attachments>(attachments)...);
return Own<T>(&value, *bundle);
}
template <typename T, typename... Attachments>
Own<Decay<T>> attachVal(T&& value, Attachments&&... attachments) {
auto bundle = new _::DisposableOwnedBundle<T, Attachments...>(
kj::fwd<T>(value), kj::fwd<Attachments>(attachments)...);
return Own<Decay<T>>(&bundle->first, *bundle);
}
} // namespace kj
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment