Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 115 additions & 8 deletions inkcpp/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,76 @@

namespace ink::runtime::internal
{
template<typename T, bool dynamic, size_t initialCapacity>
class managed_array {
public:
managed_array() : _capacity{initialCapacity}, _size{0}{
if constexpr (dynamic) {
_dynamic_data = new T[initialCapacity];
}
}

const T& operator[](size_t i) const { return data()[i]; }
T& operator[](size_t i) { return data()[i]; }
const T* data() const {
if constexpr (dynamic) {
return _dynamic_data;
} else {
return _static_data;
}
}
T* data() {
if constexpr (dynamic) {
return _dynamic_data;
} else {
return _static_data;
}
}
const T* begin() const { return data(); }
T* begin() { return data(); }
const T* end() const { return data() + _size; }
T* end() { return data() + _size; }
const T& back() const { return end()[-1]; }
T& back() { return end()[-1]; }

const size_t size() const { return _size; }
const size_t capacity() const { return _capacity; }
T& push() {
if constexpr (dynamic) {
if (_size == _capacity) { extend(); }
} else {
ink_assert(_size <= _capacity, "Stack Overflow!");
}
return data()[_size++];
}
void clear() { _size = 0; }

void extend();
private:

if_t<dynamic, char, T> _static_data[dynamic ? 1 : initialCapacity];
T* _dynamic_data = nullptr;
size_t _capacity;
size_t _size;
};

template<typename T, bool dynamic, size_t initialCapacity>
void managed_array<T, dynamic, initialCapacity>::extend()
{
static_assert(dynamic, "Can only extend if array is dynamic!");
size_t new_capacity = 1.5f * _capacity;
if (new_capacity < 5) { new_capacity = 5; }
T* new_data = new T[new_capacity];

for(size_t i = 0; i < _capacity; ++i) {
new_data[i] = _dynamic_data[i];
}

delete[] _dynamic_data;
_dynamic_data = new_data;
_capacity = new_capacity;
}

template<typename T>
class basic_restorable_array
{
Expand Down Expand Up @@ -44,6 +114,11 @@ namespace ink::runtime::internal

protected:
inline T* buffer() { return _array; }
void set_new_buffer(T* buffer, size_t capacity) {
_array = buffer;
_temp = buffer + capacity/2;
_capacity = capacity/2;
}

private:
inline void check_index(size_t index) const { inkAssert(index < capacity(), "Index out of range!"); }
Expand All @@ -52,14 +127,14 @@ namespace ink::runtime::internal
bool _saved;

// real values live here
T* const _array;
T* _array;

// we store values here when we're in save mode
// they're copied on a call to forget()
T* const _temp;
T* _temp;

// size of both _array and _temp
const size_t _capacity;
size_t _capacity;

// null
const T _null;
Expand Down Expand Up @@ -161,20 +236,52 @@ namespace ink::runtime::internal
template<typename T>
class allocated_restorable_array : public basic_restorable_array<T>
{
using base = basic_restorable_array<T>;
public:
allocated_restorable_array(size_t capacity, const T &nullValue)
: basic_restorable_array<T>(new T[capacity * 2], capacity * 2, nullValue)
{
allocated_restorable_array(const T& initial, const T& nullValue)
: basic_restorable_array<T>(0, 0, nullValue), _initialValue{initial}, _nullValue{nullValue},
_buffer{nullptr}
{}
allocated_restorable_array(size_t capacity, const T& initial, const T &nullValue)
: basic_restorable_array<T>(new T[capacity * 2], capacity * 2, nullValue),
_initialValue{initial},
_nullValue{nullValue}
{
_buffer = this->buffer();
this->clear(_initialValue);
}

void resize(size_t n) {
size_t new_capacity = 2 * n;
T* new_buffer = new T[new_capacity];
if (_buffer) {
for(size_t i = 0; i < base::capacity(); ++i) {
new_buffer[i] = _buffer[i];
// copy temp
new_buffer[i + base::capacity()] = _buffer[i + base::capacity()];
}
delete[] _buffer;
}
for(size_t i = base::capacity(); i < new_capacity; ++i) {
new_buffer[i] = _initialValue;
new_buffer[i+base::capacity()] = _nullValue;
}

_buffer = new_buffer;
this->set_new_buffer(_buffer, new_capacity);
}

~allocated_restorable_array()
{
delete[] _buffer;
_buffer = nullptr;
if(_buffer) {
delete[] _buffer;
_buffer = nullptr;
}
}

private:
T _initialValue;
T _nullValue;
T* _buffer;
};
}
4 changes: 3 additions & 1 deletion inkcpp/collections/restorable.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,9 @@ namespace ink::runtime::internal

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? */ }
virtual void overflow(ElementType*& buffer, size_t& size) {
throw ink_exception("Restorable run out of memory!");
}

private:
template<typename Predicate>
Expand Down
2 changes: 1 addition & 1 deletion inkcpp/globals_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ink::runtime::internal
{
globals_impl::globals_impl(const story_impl* story)
: _num_containers(story->num_containers())
, _visit_counts(_num_containers, ~0)
, _visit_counts(_num_containers, 0, ~0)
, _owner(story)
, _runners_start(nullptr)
, _globals_initialized(false)
Expand Down
3 changes: 1 addition & 2 deletions inkcpp/globals_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,9 @@ namespace ink::runtime::internal
// Allocated string table (shared by all runners using this global store)
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;
internal::stack<abs(config::limitGlobalVariables), config::limitGlobalVariables < 0> _variables;
bool _globals_initialized;
};
}
40 changes: 18 additions & 22 deletions inkcpp/runner_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,20 @@ namespace ink::runtime::internal

choice& runner_impl::add_choice()
{
inkAssert(_num_choices < MAX_CHOICES, "Ran out of choice storage!");
return _choices[_num_choices++];
inkAssert(config::maxChoices < 0 || _choices.size() < config::maxChoices,
"Ran out of choice storage!");
return _choices.push();
}

void runner_impl::clear_choices()
{
// TODO: Garbage collection?
_num_choices = 0;
// TODO: Garbage collection? ? which garbage ?
_choices.clear();
}

void runner_impl::clear_tags()
{
_num_tags = 0;
_tags.clear();
}

void runner_impl::jump(ip_t dest, bool record_visits)
Expand Down Expand Up @@ -246,8 +247,8 @@ namespace ink::runtime::internal
}

runner_impl::runner_impl(const story_impl* data, globals global)
: _story(data), _globals(global.cast<globals_impl>()), _container(~0), _threads(~0),
_threadDone(nullptr, (ip_t)~0), _backup(nullptr), _done(nullptr), _choices()
: _story(data), _globals(global.cast<globals_impl>()), _container(~0),
_backup(nullptr), _done(nullptr), _choices()
{
_ptr = _story->instructions();
bEvaluationMode = false;
Expand Down Expand Up @@ -367,7 +368,7 @@ namespace ink::runtime::internal

void runner_impl::choose(size_t index)
{
inkAssert(index < _num_choices, "Choice index out of range");
inkAssert(index < _choices.size(), "Choice index out of range");

// Get the choice
const auto& c = _choices[index];
Expand All @@ -380,7 +381,7 @@ namespace ink::runtime::internal
if (choiceThread == ~0)
prev = _done;
else
prev = _threadDone.get(choiceThread);
prev = _threads.get(choiceThread);

// Make sure we have a previous pointer
inkAssert(prev != nullptr, "No 'done' point recorded before finishing choice output");
Expand All @@ -392,7 +393,6 @@ namespace ink::runtime::internal
// Collapse callstacks to the correct thread
_stack.collapse_to_thread(choiceThread);
_threads.clear();
_threadDone.clear(nullptr);

// Jump to destination and clear choice list
jump(_story->instructions() + _choices[index].path());
Expand All @@ -409,17 +409,17 @@ namespace ink::runtime::internal

bool runner_impl::has_tags() const
{
return _num_tags > 0;
return _tags.size() > 0;
}

size_t runner_impl::num_tags() const
{
return _num_tags;
return _tags.size();
}

const char* runner_impl::get_tag(size_t index) const
{
inkAssert(index < _num_tags, "Tag index exceeds _num_tags");
inkAssert(index < _tags.size(), "Tag index exceeds _num_tags");
return _tags[index];
}

Expand Down Expand Up @@ -892,7 +892,7 @@ namespace ink::runtime::internal
for(;sc;--sc) { _output << stack[sc-1]; }

// Create choice and record it
add_choice().setup(_output, _globals->strings(), _num_choices, path, current_thread());
add_choice().setup(_output, _globals->strings(), _choices.size(), path, current_thread());
} break;
case Command::START_CONTAINER_MARKER:
{
Expand Down Expand Up @@ -978,7 +978,7 @@ namespace ink::runtime::internal
} break;
case Command::TAG:
{
_tags[_num_tags++] = read<const char*>();
_tags.push() = read<const char*>();
} break;
default:
inkAssert(false, "Unrecognized command!");
Expand Down Expand Up @@ -1023,7 +1023,7 @@ namespace ink::runtime::internal
_done = ptr;
}
else {
_threadDone.set(curr, ptr);
_threads.set(curr, ptr);
}
}

Expand All @@ -1033,10 +1033,9 @@ namespace ink::runtime::internal
_output.clear();
_stack.clear();
_threads.clear();
_threadDone.clear(nullptr);
bEvaluationMode = false;
_saved = false;
_num_choices = 0;
_choices.clear();
_ptr = nullptr;
_done = nullptr;
_container.clear();
Expand All @@ -1050,7 +1049,7 @@ namespace ink::runtime::internal
_eval.mark_strings(strings);

// Take into account choice text
for (int i = 0; i < _num_choices; i++)
for (int i = 0; i < _choices.size(); i++)
strings.mark_used(_choices[i]._text);
}

Expand All @@ -1066,7 +1065,6 @@ namespace ink::runtime::internal
_globals->save();
_eval.save();
_threads.save();
_threadDone.save();
bSavedEvaluationMode = bEvaluationMode;

// Not doing this anymore. There can be lingering stack entries from function returns
Expand All @@ -1084,7 +1082,6 @@ namespace ink::runtime::internal
_globals->restore();
_eval.restore();
_threads.restore();
_threadDone.restore();
bEvaluationMode = bSavedEvaluationMode;

// Not doing this anymore. There can be lingering stack entries from function returns
Expand All @@ -1105,7 +1102,6 @@ namespace ink::runtime::internal
_globals->forget();
_eval.forget();
_threads.forget();
_threadDone.forget();

// Nothing to do for eval stack. It should just stay as it is

Expand Down
Loading