Skip to content

Instantly share code, notes, and snippets.

@ecatmur
Last active February 11, 2021 17:38
Show Gist options
  • Save ecatmur/48595300c0fa72cf0b1221e77c3cf0b5 to your computer and use it in GitHub Desktop.
Save ecatmur/48595300c0fa72cf0b1221e77c3cf0b5 to your computer and use it in GitHub Desktop.
Library relocate
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4158.pdf
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0023r0.pdf
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1029r3.pdf
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1144r5.html
#include <type_traits>
#include <utility>
struct relocates{};
template<class T> constexpr bool is_relocatable_v = std::is_constructible_v<T, relocates, T*>;
template<class T>
T relocate(T* ptr) noexcept(is_relocatable_v<T> || std::is_nothrow_move_constructible_v<T>) {
if constexpr (is_relocatable_v<T>) {
return T(relocates(), ptr); // magic: ends life of *ptr w/o calling ~T()
}
else {
T ret(std::move(*ptr));
ptr->~T();
return ret; // NRVO
}
}
#include <cassert>
#include <iostream>
#include <memory>
#include <new>
#include <string>
template<class T>
class nonnull_ptr {
std::unique_ptr<T> ptr;
public:
nonnull_ptr(std::unique_ptr<T> ptr) : ptr(std::move(ptr)) { assert(this->ptr); }
nonnull_ptr(nonnull_ptr&&) = delete;
nonnull_ptr(relocates, nonnull_ptr* r) : ptr(relocate(&r->ptr)) {}
T& operator*() { return *ptr; }
T* operator->() { return ptr; }
};
template<class T>
class optional {
union { char disengaged; T value; };
bool engaged = false;
public:
optional() : disengaged{} {}
optional(optional&& rhs) {
if ((engaged = std::exchange(rhs.engaged, false)))
new (&value) T(relocate(&rhs.value));
}
~optional() {
if (engaged)
value.~T();
}
template<class... Args>
T& emplace(Args&&... args) {
if (std::exchange(engaged, true))
value.~T();
new (&value) T(std::forward<Args>(args)...);
return value;
}
T& operator*() { return value; }
};
int main() {
optional<std::string> o;
o.emplace("hello");
optional<nonnull_ptr<std::string>> p;
p.emplace(std::make_unique<std::string>("world"));
auto q = std::move(o);
auto r = std::move(p);
std::cout << *q << ' ' << **r << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment