Skip to content
48 changes: 29 additions & 19 deletions inkcpp/collections/restorable.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,24 @@ namespace ink::runtime::internal

// Reverse find
template<typename Predicate>
const ElementType* reverse_find(Predicate predicate) const
ElementType* reverse_find(Predicate predicate) {
return reverse_find_impl(predicate);
}

template<typename Predicate>
const ElementType* reverse_find(Predicate predicate) const {
return reverse_find_impl(predicate);
}

template<typename IsNullPredicate>
size_t size(IsNullPredicate isNull) const
{
if (_pos == 0) {
return nullptr;
return 0;
}

size_t count = 0;

// Start at the end
size_t i = _pos;
do
Expand All @@ -301,27 +313,30 @@ namespace ink::runtime::internal
i--;

// Run callback
if (predicate(_buffer[i]))
return &_buffer[i];
if(!isNull(_buffer[i]))
count++;

// Jump over saved data
if (i == _save)
i = _jump;

} while (i > 0);

return nullptr;
return count;
}

template<typename IsNullPredicate>
size_t size(IsNullPredicate isNull) const
protected:
// Called when we run out of space in buffer.
virtual void overflow(ElementType*& buffer, size_t& size) { throw 0; /* TODO: What to do here? Throw something more useful? */ }

private:
template<typename Predicate>
ElementType* reverse_find_impl(Predicate predicate) const
{
if (_pos == 0) {
return 0;
return nullptr;
}

size_t count = 0;

// Start at the end
size_t i = _pos;
do
Expand All @@ -330,23 +345,18 @@ namespace ink::runtime::internal
i--;

// Run callback
if(!isNull(_buffer[i]))
count++;
if (predicate(_buffer[i]))
return &_buffer[i];

// Jump over saved data
if (i == _save)
i = _jump;

} while (i > 0);

return count;
return nullptr;
}

protected:
// Called when we run out of space in buffer.
virtual void overflow(ElementType*& buffer, size_t& size) { throw 0; /* TODO: What to do here? Throw something more useful? */ }

private:
// Data buffer. Collection is stored here
ElementType* _buffer;

Expand All @@ -360,4 +370,4 @@ namespace ink::runtime::internal
size_t _jump;
size_t _save;
};
}
}
75 changes: 74 additions & 1 deletion inkcpp/globals_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,79 @@ namespace ink::runtime::internal
return _variables.get(name);
}

value* globals_impl::get_variable(hash_t name) {
return _variables.get(name);
}

template<typename T, const T* (value::*FN)() const, typename ... TYPES>
auto fetch_variable( const value* v, TYPES ... types) {
return v && ((v->get_data_type() == types) || ...)
? (v->*FN)()
: nullptr;
}
template<typename T, T* (value::*FN)(), typename ... TYPES>
auto fetch_variable(value* v, TYPES ... types) {
return v && ((v->get_data_type() == types) || ...)
? (v->*FN)()
: nullptr;
}

const uint32_t* globals_impl::get_uint(hash_t name) const {
return fetch_variable<uint32_t, &value::as_uint_ptr>(get_variable(name), data_type::uint32);
}
bool globals_impl::set_uint(hash_t name, uint32_t val) {
uint32_t* p = fetch_variable<uint32_t, &value::as_uint_ptr>(get_variable(name), data_type::uint32);
if (p == nullptr) { return false; }
*p = val;
return true;
}

const int32_t* globals_impl::get_int(hash_t name) const {
return fetch_variable<int32_t, &value::as_int_ptr>(get_variable(name), data_type::int32);
}
bool globals_impl::set_int(hash_t name, int32_t val) {
int32_t* p = fetch_variable<int32_t, &value::as_int_ptr>(get_variable(name), data_type::int32);
if (p == nullptr) { return false; }
*p = val;
return true;
}

const float* globals_impl::get_float(hash_t name) const {
return fetch_variable<float, &value::as_float_ptr>(get_variable(name), data_type::float32);
}
bool globals_impl::set_float(hash_t name, float val) {
float* p = fetch_variable<float, &value::as_float_ptr>(get_variable(name), data_type::float32);
if (p == nullptr) { return false; }
*p = val;
return true;
}

const char * const * globals_impl::get_str(hash_t name) const {
const value* v = get_variable(name);
if (v->type() != value_type::string) { return nullptr; }
return v->as_str_ptr(_strings);
}
bool globals_impl::set_str(hash_t name, const char* val) {
value* v = get_variable(name);
if (v->type() == value_type::string)
{
size_t size = 0;
char* ptr;
for(const char*i = val; *i; ++i) { ++size; }
char* new_string = strings().create(size + 1);
strings().mark_used(new_string);
ptr = new_string;
for(const char* i = val; *i; ++i) {
*ptr++ = *i;
}
internal::data d;
d.set_string(new_string, true);
*v = internal::value(d);
return true;
}
return false;
}

void globals_impl::initialize_globals(runner_impl* run)
{
// If no way to move there, then there are no globals.
Expand Down Expand Up @@ -118,4 +191,4 @@ namespace ink::runtime::internal
_visit_counts.forget();
_variables.forget();
}
}
}
23 changes: 18 additions & 5 deletions inkcpp/globals_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ namespace ink::runtime::internal
globals_impl(const story_impl*);
virtual ~globals_impl() { }

virtual void dummy() override { }
protected:
const uint32_t* get_uint(hash_t name) const override;
bool set_uint(hash_t name, uint32_t value) override;

const int32_t* get_int(hash_t name) const override;
bool set_int(hash_t name, int32_t value) override;

const float* get_float(hash_t name) const override;
bool set_float(hash_t name, float value) override;

const char * const * get_str(hash_t name) const override;
bool set_str(hash_t name, const char* value) override;

public:
// Records a visit to a container
Expand All @@ -37,6 +48,7 @@ namespace ink::runtime::internal

// gets a global variable
const value* get_variable(hash_t name) const;
value* get_variable(hash_t name);

// checks if globals are initialized
bool are_globals_initialized() const { return _globals_initialized; }
Expand All @@ -46,18 +58,19 @@ namespace ink::runtime::internal

// gets the allocated string table
inline string_table& strings() { return _strings; }

// run garbage collection
void gc();

// == Save/Restore ==
void save();
void restore();
void forget();

private:
// Store the number of containers. This is the length of most of our lists
const uint32_t _num_containers;

// Visit count array
internal::allocated_restorable_array<uint32_t> _visit_counts;

Expand All @@ -75,12 +88,12 @@ namespace ink::runtime::internal
runner_entry* _runners_start;

// Allocated string table (shared by all runners using this global store)
string_table _strings;
mutable string_table _strings;

// Global variables (TODO: Max 50?)
// Implemented as a stack (slow lookup) because it has save/restore functionality.
// If I could create an avl tree with save/restore, that'd be great but seems super complex.
internal::stack<50> _variables;
bool _globals_initialized;
};
}
}
87 changes: 85 additions & 2 deletions inkcpp/include/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,98 @@

namespace ink::runtime
{
class globals_interface;
namespace internal { class globals_impl;}

/**
* Represents a global store to be shared amongst ink runners.
* Stores global variable values, visit counts, turn counts, etc.
*/
class globals_interface
{
public:
// No public interface yet
virtual void dummy() = 0;

/**
* @brief Access global variable of Ink runner.
* @param name name of variable, as defined in InkScript
* @tparam T c++ type of variable
* @return nullopt if variable won't exist or type won't match
*/
template<typename T>
optional<T> get(const char* name) const {
static_assert(
internal::always_false<T>::value,
"Requested Type is not supported");
}

/**
* @brief Write new value in global store.
* @param name name of variable, as defined in InkScript
* @tparam T c++ type of variable
* @return true on success
*/
template<typename T>
bool set(const char* name, const T& val) {
static_assert(
internal::always_false<T>::value,
"Requested Type is not supported");
return false;
}

virtual ~globals_interface() = default;

protected:
virtual const uint32_t* get_uint(hash_t name) const = 0;
virtual bool set_uint(hash_t name, uint32_t val) = 0;
virtual const int32_t* get_int(hash_t name) const = 0;
virtual bool set_int(hash_t name, int32_t val) = 0;
virtual const float* get_float(hash_t name) const = 0;
virtual bool set_float(hash_t name, float val) = 0;
virtual const char* const * get_str(hash_t name) const = 0;
virtual bool set_str(hash_t name, const char* val) = 0;
};

template<>
inline optional<uint32_t> globals_interface::get<uint32_t>(const char* name) const {
const uint32_t* p = get_uint(hash_string(name));
if (p) { return {*p}; }
return {nullopt};
}
template<>
inline bool globals_interface::set<uint32_t>(const char* name, const uint32_t& val) {
return set_uint(hash_string(name), val);
}

template<>
inline optional<int32_t> globals_interface::get<int32_t>(const char* name) const {
const int32_t* p = get_int(hash_string(name));
if (p) { return {*p}; }
return {nullopt};
}
template<>
inline bool globals_interface::set<int32_t>(const char* name, const int32_t& val) {
return set_int(hash_string(name), val);
}

template<>
inline optional<float> globals_interface::get<float>(const char* name) const {
const float* p = get_float(hash_string(name));
if (p) { return {*p}; }
return {nullopt};
}
template<>
inline bool globals_interface::set<float>(const char* name, const float& val) {
return set_float(hash_string(name), val);
}

template<>
inline optional<const char*>globals_interface::get<const char*>(const char* name) const {
const char * const * p = get_str(hash_string(name));
if (p) { return {*p}; }
return {nullopt};
}
template<>
inline bool globals_interface::set<const char*>(const char* name, const char * const & val) {
return set_str(hash_string(name), val);
}
}
Loading