Files
integration/luprex/core/cpp/luasnap.cpp

173 lines
4.4 KiB
C++

#include "luasnap.hpp"
#include <iostream>
#include <cassert>
struct BlockHeader {
BlockHeader *prev_;
BlockHeader *next_;
int32_t sanity_; // 0x12345678 only when linked.
size_t size_;
bool in_use_;
void *snapshot_;
};
size_t blocksize(size_t base) {
return base + sizeof(BlockHeader);
}
BlockHeader *pointer_to_header(void *ptr) {
return (BlockHeader*)(((char *)ptr) - sizeof(BlockHeader));
}
void *header_to_pointer(BlockHeader *blk) {
return (void *)(((char *)blk) + sizeof(BlockHeader));
}
class LuaSnapData {
public:
lua_State *state_;
bool have_snapshot_;
BlockHeader sentinel_;
LuaSnapData();
~LuaSnapData();
lua_State *state() const { return state_; }
bool have_snapshot() const { return have_snapshot_; }
void snapshot();
void rollback();
void link(BlockHeader *blk);
void unlink(BlockHeader *blk);
void *allocf(void *ptr, size_t osize, size_t nsize);
};
void *lsd_alloc_f(void *lsd, void *ptr, size_t osize, size_t nsize) {
return ((LuaSnapData*)lsd)->allocf(ptr, osize, nsize);
}
LuaSnapData::LuaSnapData() {
sentinel_.prev_ = &sentinel_;
sentinel_.next_ = &sentinel_;
sentinel_.size_ = 0;
sentinel_.in_use_ = false;
sentinel_.snapshot_ = 0;
have_snapshot_ = false;
state_ = lua_newstate(lsd_alloc_f, (void*)this);
}
LuaSnapData::~LuaSnapData() {
std::cerr << "LuaSnapData destructor not implemented." << std::endl;
exit(1);
}
void LuaSnapData::snapshot() {
assert(!have_snapshot_);
for (BlockHeader *blk = sentinel_.next_; blk != &sentinel_; blk = blk->next_) {
assert(blk->in_use_);
blk->snapshot_ = malloc(blk->size_);
memcpy(blk->snapshot_, header_to_pointer(blk), blk->size_);
}
have_snapshot_ = true;
}
void LuaSnapData::rollback() {
assert(have_snapshot_);
for (BlockHeader *blk = sentinel_.next_; blk != &sentinel_; ) {
BlockHeader *next = blk->next_;
if (blk->snapshot_) {
memcpy(header_to_pointer(blk), blk->snapshot_, blk->size_);
free(blk->snapshot_);
blk->snapshot_ = nullptr;
blk->in_use_ = true;
} else {
assert(blk->in_use_);
unlink(blk);
free(blk);
}
blk = next;
}
have_snapshot_ = false;
}
void LuaSnapData::link(BlockHeader *blk) {
blk->prev_ = sentinel_.prev_;
blk->next_ = &sentinel_;
blk->prev_->next_ = blk;
blk->next_->prev_ = blk;
blk->sanity_ = 0x12345678;
}
void LuaSnapData::unlink(BlockHeader *blk) {
blk->prev_->next_ = blk->next_;
blk->next_->prev_ = blk->prev_;
blk->prev_ = nullptr;
blk->next_ = nullptr;
blk->sanity_ = 0;
}
void *LuaSnapData::allocf(void *ptr, size_t osize, size_t nsize) {
if (nsize == 0) {
if (ptr == 0) return nullptr;
BlockHeader *blk = pointer_to_header(ptr);
assert(blk->sanity_ = 0x12345678);
assert(blk->in_use_);
if (blk->snapshot_ == nullptr) {
unlink(blk);
free(blk);
} else {
blk->in_use_ = false;
}
return nullptr;
} else if (ptr == NULL) {
BlockHeader *blk = (BlockHeader*)malloc(blocksize(nsize));
link(blk);
blk->size_ = nsize;
blk->in_use_ = true;
blk->snapshot_ = nullptr;
return header_to_pointer(blk);
} else {
BlockHeader *blk = pointer_to_header(ptr);
assert(blk->sanity_ = 0x12345678);
assert(blk->in_use_);
if (blk->snapshot_ == nullptr) {
unlink(blk);
blk = (BlockHeader*)realloc(blk, blocksize(nsize));
blk->size_ = nsize;
link(blk);
return header_to_pointer(blk);
} else {
BlockHeader *nblk = (BlockHeader*)malloc(blocksize(nsize));
memcpy(nblk, blk, (blk->size_ < nsize) ? blk->size_ : nsize);
blk->in_use_ = false;
link(nblk);
nblk->size_ = nsize;
nblk->in_use_ = true;
nblk->snapshot_ = nullptr;
return header_to_pointer(nblk);
}
}
}
LuaSnap::LuaSnap() {
data_ = new LuaSnapData;
state_ = data_->state();
}
LuaSnap::~LuaSnap() {
delete data_;
}
bool LuaSnap::have_snapshot() const {
return data_->have_snapshot();
}
void LuaSnap::snapshot() {
data_->snapshot();
}
void LuaSnap::rollback() {
data_->rollback();
}