xo-alloc: mutation log tracking in working state + unit test

This commit is contained in:
Roland Conybeare 2025-08-05 11:08:36 -05:00
commit 5d2fcf6498
25 changed files with 735 additions and 185 deletions

View file

@ -1,37 +0,0 @@
/* @file BooleanObj.hpp
*
* author: Roland Conybeare, Aug 2025
*/
#include "xo/alloc/Object.hpp"
namespace xo {
namespace obj {
/** @class BooleanObj
* @brief Boxed wrapper for a boolean value
**/
class BooleanObj : public Object {
public:
/** @return instance representing boolean with truth-value @p x **/
static gp<BooleanObj> boolean_obj(bool x);
static gp<BooleanObj> true_obj();
static gp<BooleanObj> false_obj();
bool value() const { return value_; }
// inherited from Object..
virtual std::size_t _shallow_size() const override;
virtual Object * _shallow_copy() const override;
virtual std::size_t _forward_children() override;
private:
explicit BooleanObj(bool x) : value_{x} {}
private:
bool value_;
};
}
}
/* end BooleanObj.hpp */

View file

@ -15,7 +15,12 @@ namespace xo {
Integer() = default;
explicit Integer(int_type x);
/** create instance holding integer value @p x **/
static gp<Integer> make(int_type x);
/** downcast from @p x iff x is actually an Integer. Otherwise nullptr **/
static gp<Integer> from(gp<Object> x);
int_type value() const { return value_; }
// inherited from Object..
virtual std::size_t _shallow_size() const override;

View file

@ -18,14 +18,36 @@ namespace xo {
/** @return list with first element @p car, and tail @p cdr **/
static gp<List> cons(gp<Object> car, gp<List> cdr);
/** @return list with single element @p x1 **/
template <typename T>
static gp<List> list(T && x1) {
return List::cons(x1, nil);
}
/** @return list with elements @p x1, ..., @p rest in argument order **/
template <typename T, typename... Rest>
static gp<List> list(T && x1, Rest &&... rest) {
return List::cons(x1, list(rest...));
}
/** @return true iff list is empty **/
bool is_nil() const { return this == nil.ptr(); }
gp<Object> head() const { return head_; }
gp<List> tail() const { return tail_; }
gp<List> rest() const { return rest_; }
/** @return first element in list; synonym for @ref head **/
gp<Object> car() const { return head_; }
/** @return remainder of list after first element; synonym for @ref rest **/
gp<Object> cdr() const { return rest_; }
/** @return number of top-level elements in this list **/
std::size_t size() const;
gp<Object> list_ref(std::size_t i) const;
void assign_head(gp<Object> head);
void assign_rest(gp<List> rest);
// inherited from Object..
virtual std::size_t _shallow_size() const override;
@ -33,11 +55,11 @@ namespace xo {
virtual std::size_t _forward_children() override;
private:
List(gp<Object> head, gp<List> tail);
List(gp<Object> head, gp<List> rest);
private:
gp<Object> head_;
gp<List> tail_;
gp<List> rest_;
};
}
} /*namespace xo*/

View file

@ -12,7 +12,7 @@ namespace xo {
public:
enum Owner { unique, shared };
/** donwcase from @p x iff x is actually a String. Otherwise nullptr **/
/** donwcast from @p x iff x is actually a String. Otherwise nullptr **/
static gp<String> from(gp<Object> x);
/** create copy of string @p s, using allocator @ref Object::mm **/

View file

@ -15,6 +15,11 @@ namespace xo {
return new (MMPtr(mm)) Integer(x);
}
gp<Integer>
Integer::from(gp<Object> x) {
return dynamic_cast<Integer*>(x.ptr());
}
std::size_t
Integer::_shallow_size() const {
return sizeof(Integer);
@ -23,7 +28,6 @@ namespace xo {
Object *
Integer::_shallow_copy() const {
Cpof cpof(this);
return new (cpof) Integer(*this);
}

View file

@ -4,13 +4,14 @@
**/
#include "List.hpp"
#include "xo/indentlog/scope.hpp"
#include <cassert>
#include <cstddef>
namespace xo {
namespace obj {
List::List(gp<Object> head, gp<List> tail)
: head_{head}, tail_{tail} {}
List::List(gp<Object> head, gp<List> rest)
: head_{head}, rest_{rest} {}
gp<List>
List::nil = new List(nullptr, nullptr);
@ -27,7 +28,7 @@ namespace xo {
gp<const List> l(this);
while (!l->is_nil()) {
++retval;
l = l->tail();
l = l->rest();
}
return retval;
@ -40,7 +41,7 @@ namespace xo {
while (i > 0) {
assert(!(rem->is_nil()));
rem = rem->tail();
rem = rem->rest();
--i;
}
@ -48,6 +49,18 @@ namespace xo {
}
void
List::assign_head(gp<Object> head)
{
Object::assign_member(this, &(this->head_), head);
}
void
List::assign_rest(gp<List> tail)
{
Object::assign_member(this, &(this->rest_), tail);
}
std::size_t
List::_shallow_size() const {
return sizeof(List);
@ -55,6 +68,8 @@ namespace xo {
Object *
List::_shallow_copy() const {
scope log(XO_DEBUG(Object::mm->debug_flag()));
assert(!(this->is_nil()));
Cpof cpof(this);
@ -65,7 +80,7 @@ namespace xo {
std::size_t
List::_forward_children() {
Object::_forward_inplace(head_);
Object::_forward_inplace(tail_);
Object::_forward_inplace(rest_);
return List::_shallow_size();
}
}

View file

@ -31,14 +31,12 @@ namespace xo {
}
gp<String>
String::from(gp<Object> x)
{
String::from(gp<Object> x) {
return dynamic_cast<String*>(x.ptr());
}
gp<String>
String::copy(const char * s)
{
String::copy(const char * s) {
return copy(Object::mm, s);
}

View file

@ -4,7 +4,8 @@ set(SELF_EXE utest.object)
set(SELF_SRCS
object_utest_main.cpp
String.test.cpp
List.test.cpp)
List.test.cpp
GC.test.cpp)
xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS})
xo_self_dependency(${SELF_EXE} xo_object)

View file

@ -17,6 +17,7 @@ namespace xo {
using xo::obj::List;
using xo::obj::String;
using xo::gc::GC;
using xo::gc::generation_result;
using xo::gc::generation;
namespace {
@ -117,8 +118,8 @@ namespace xo {
REQUIRE(s.ptr());
REQUIRE(strcmp(s->c_str(), tc.v_.at(i).at(j).c_str()) == 0);
REQUIRE(gc->generation_of(reinterpret_cast<std::byte*>(s.ptr()))
== generation::nursery);
REQUIRE(gc->tospace_generation_of(reinterpret_cast<std::byte*>(s.ptr()))
== generation_result::nursery);
}
}
@ -142,8 +143,8 @@ namespace xo {
REQUIRE(s.ptr());
REQUIRE(strcmp(s->c_str(), tc.v_.at(i).at(j).c_str()) == 0);
REQUIRE(gc->generation_of(reinterpret_cast<std::byte*>(s.ptr()))
== generation::tenured);
REQUIRE(gc->tospace_generation_of(reinterpret_cast<std::byte*>(s.ptr()))
== generation_result::tenured);
}
}
@ -168,8 +169,8 @@ namespace xo {
REQUIRE(s.ptr());
REQUIRE(strcmp(s->c_str(), tc.v_.at(i).at(j).c_str()) == 0);
REQUIRE(gc->generation_of(reinterpret_cast<std::byte*>(s.ptr()))
== generation::tenured);
REQUIRE(gc->tospace_generation_of(reinterpret_cast<std::byte*>(s.ptr()))
== generation_result::tenured);
}
}