Emulate borrow checker in C++ with stateful metaprogramming

bhuztez
bhuztez
Jul 9, 2017 · 3 min read
// example0.cpp
#include "borrow.hpp"

int
main() {
using borrow::ended;

struct $ {
struct Lifetime;
};

static_assert(not ended(${}, 0));

struct $::Lifetime {
struct Ended;
};

static_assert(not ended(${}, 0)); // compiler error here
}
// example1.cpp
#include <new>
#include <type_traits>
#include <utility>
#include "borrow.hpp"

template<typename T>
struct Container {
char buf[sizeof(T)];

void
write(T&& item) {
T *ptr = static_cast<T *>(static_cast<void *>(buf));
new (ptr) T(::std::move(item));
}

T
read() {
T *ptr = static_cast<T *>(static_cast<void *>(buf));
T item = ::std::move(*ptr);
ptr->~T();
return item;
}

T&
get() {
T *ptr = static_cast<T *>(static_cast<void *>(buf));
return *ptr;
}

T const&
get() const {
T *ptr = static_cast<T *>(static_cast<void *>(buf));
return *ptr;
}
};

template<typename T, typename $,
bool A = ::borrow::available(${}),
typename = typename ::std::enable_if<A>::type>
auto
get(::borrow::BorrowPtr<Container<T>,$> ptr) {
return ::borrow::BorrowPtr<T,$> { (*ptr).get() };
}


int
main() {
auto c = Container<int> {};
c.write(0);

BEGIN_LIFETIME($);
auto p = ::borrow::borrow_mut<$>(c);

BEGIN_LIFETIME($1);
auto p1 = ::borrow::borrow_mut<$1>(p);

auto p2 = get(p1);

*p2 = 1;

END_LIFETIME($1);

*p2; // compiler error here

END_LIFETIME($);
}
// mut3.cpp
#include "borrow.hpp"

int
main() {
using ::borrow::borrow;
using ::borrow::borrow_mut;

int value = 1;
BEGIN_LIFETIME($1);
BEGIN_LIFETIME($2);
BEGIN_LIFETIME($3);

auto p1 = borrow_mut<$1>(value);
auto p2 = borrow<$2>(p1);
auto p3 = borrow<$3>(p1);
*p2;
static_assert(::std::is_same<decltype(*p2), int const&>::value);

END_LIFETIME($2);
*p3;
*p2; // compiler error here
END_LIFETIME($3);
END_LIFETIME($1);
}
// mut4.cpp
#include "borrow.hpp"

int
main() {
using ::borrow::borrow;
using ::borrow::borrow_mut;

int value = 1;
BEGIN_LIFETIME($1);
BEGIN_LIFETIME($2);

auto p1 = borrow_mut<$1>(value);
auto p2 = borrow<$2>(p1);
*p2;
static_assert(::std::is_same<decltype(*p2), int const&>::value);

END_LIFETIME($1);
*p2; // compiler error here
END_LIFETIME($2);
}
// mut7.cpp
#include "borrow.hpp"

int
main() {
using ::borrow::borrow;
using ::borrow::borrow_mut;

int value = 1;
BEGIN_LIFETIME($1);
BEGIN_LIFETIME($2);
BEGIN_LIFETIME($3);
BEGIN_LIFETIME($4);
BEGIN_LIFETIME($5);

auto p1 = borrow_mut<$1>(value);
auto p2 = borrow_mut<$2>(p1);
END_LIFETIME($2);

auto p3 = borrow<$3>(p1);
END_LIFETIME($3);

auto p4 = borrow_mut<$4>(p1);
auto p5 = borrow<$5>(p1); // compiler error here

END_LIFETIME($1);
END_LIFETIME($4);
END_LIFETIME($5);
}
// mut8.cpp
#include "borrow.hpp"

int
main() {
using ::borrow::borrow;
using ::borrow::borrow_mut;

int value = 1;
BEGIN_LIFETIME($1);
BEGIN_LIFETIME($2);
BEGIN_LIFETIME($3);
BEGIN_LIFETIME($4);
BEGIN_LIFETIME($5);
BEGIN_LIFETIME($6);
BEGIN_LIFETIME($7);

auto p1 = borrow_mut<$1>(value);
auto p2 = borrow<$2>(p1);
auto p3 = borrow<$3>(p1);
END_LIFETIME($2);
END_LIFETIME($3);

auto p4 = borrow_mut<$4>(p1);
END_LIFETIME($4);

auto p5 = borrow<$5>(p1);
auto p6 = borrow<$6>(p1);
auto p7 = borrow_mut<$7>(p1); // compiler error here

END_LIFETIME($1);
END_LIFETIME($5);
END_LIFETIME($6);
END_LIFETIME($7);
}
// mut9.cpp
#include "borrow.hpp"

int
main() {
using ::borrow::borrow;
using ::borrow::borrow_mut;

int value = 1;
BEGIN_LIFETIME($1);
BEGIN_LIFETIME($2);
BEGIN_LIFETIME($3);
BEGIN_LIFETIME($4);

auto p1 = borrow_mut<$1>(value);
*p1;
static_assert(::std::is_same<decltype(*p1), int&>::value);

auto p2 = borrow<$2>(p1);
*p1;
static_assert(::std::is_same<decltype(*p1), int const&>::value);
*p2;
END_LIFETIME($2);

*p1;
static_assert(::std::is_same<decltype(*p1), int&>::value);

auto p3 = borrow_mut<$3>(p1);
*p3;
END_LIFETIME($3);
*p1;
static_assert(::std::is_same<decltype(*p1), int&>::value);

auto p4 = borrow_mut<$4>(p1);
*p4;
*p1; // compiler error here

END_LIFETIME($1);
END_LIFETIME($4);
}

bhuztez

Written by

bhuztez

Shopping is hard, let’s reinvent the wheel

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade