diff --git a/inkcpp/array.h b/inkcpp/array.h index 9e6c51cf..a03bf369 100644 --- a/inkcpp/array.h +++ b/inkcpp/array.h @@ -12,7 +12,7 @@ #include "traits.h" #include -#include +#include namespace ink::runtime::internal { @@ -34,15 +34,16 @@ class managed_array : public snapshot_interface , _static_data{} { if constexpr (dynamic) { - if constexpr (simple) { - _dynamic_data = reinterpret_cast(new char[sizeof(T) * initialCapacity]); - inkAssert( - reinterpret_cast(_dynamic_data) % alignof(T) == 0, - "The data array has a different alignment(%d) then the contained data(%d)", - reinterpret_cast(_dynamic_data), alignof(T) - ); - } else { - _dynamic_data = new T[initialCapacity]; + if constexpr (initialCapacity > 0) { + if constexpr (simple) { + _dynamic_data + = reinterpret_cast(new (std::nothrow) char[sizeof(T) * initialCapacity]); + inkAssert(_dynamic_data != nullptr, "Out of memory in inkcpp: managed_array init failed"); + inkAssert(( ::size_t ) _dynamic_data % alignof(T) == 0); + } else { + _dynamic_data = new (std::nothrow) T[initialCapacity]; + inkAssert(_dynamic_data != nullptr, "Out of memory in inkcpp: managed_array init failed"); + } } } } @@ -55,10 +56,12 @@ class managed_array : public snapshot_interface virtual ~managed_array() { if constexpr (dynamic) { - if constexpr (simple) { - delete[] reinterpret_cast(_dynamic_data); - } else { - delete[] _dynamic_data; + if (_dynamic_data != nullptr) { + if constexpr (simple) { + delete[] reinterpret_cast(_dynamic_data); + } else { + delete[] _dynamic_data; + } } } } @@ -115,11 +118,11 @@ class managed_array : public snapshot_interface if (_size == _capacity) { extend(); } - inkAssert(_size < _capacity, "Failed to extend full dynamic array!"); } else { - inkAssert(_size < _capacity, "Try to append to a full array!"); + inkAssert(_size <= _capacity, "Try to append to a full array!"); // TODO(JBenda): Silent fail? } + inkAssert(_size < _capacity); return data()[_size++]; } @@ -282,31 +285,30 @@ void managed_array::extend(size_t capacity) if constexpr (simple) { // Warning: Allocating typed data in a char* container is potentially unsafe. We need to be sure // the alignment is compatible with the destination type... - new_data = reinterpret_cast(new char[sizeof(T) * new_capacity]); - inkAssert( - reinterpret_cast(new_data) % alignof(T) == 0, - "New allocated array for extansion is aligned(%d) but the data type has an alignment of %d", - reinterpret_cast(new_data), alignof(T) - ); + new_data = reinterpret_cast(new (std::nothrow) char[sizeof(T) * new_capacity]); + inkAssert(new_data != nullptr, "Out of memory in inkcpp: managed_array extend failed (simple)"); + inkAssert(( ::size_t ) new_data % alignof(T) == 0); // ...and we have to copy the contents byte-by-byte, since client code (_list_handouts) // type-puns between two classes with different vtbls here. Copying these elementwise would // change the stored C++ type. - memcpy(static_cast(new_data), static_cast(_dynamic_data), sizeof(T) * _size); + if (_dynamic_data) { + memcpy(new_data, _dynamic_data, sizeof(T) * _capacity); + delete[] reinterpret_cast(_dynamic_data); + } } else { // Allocate and copy typed data normally - new_data = new T[new_capacity]; + new_data = new (std::nothrow) T[new_capacity]; + inkAssert(new_data != nullptr, "Out of memory in inkcpp: managed_array extend failed (typed)"); - for (size_t i = 0; i < _capacity; ++i) { - new_data[i] = _dynamic_data[i]; + if (_dynamic_data) { + for (size_t i = 0; i < _capacity; ++i) { + new_data[i] = static_cast(_dynamic_data[i]); + } + delete[] _dynamic_data; } } - if constexpr (simple) { - delete[] reinterpret_cast(_dynamic_data); - } else { - delete[] _dynamic_data; - } _dynamic_data = new_data; _capacity = new_capacity; } diff --git a/inkcpp/collections/restorable.h b/inkcpp/collections/restorable.h index 358578e5..c6f34b74 100644 --- a/inkcpp/collections/restorable.h +++ b/inkcpp/collections/restorable.h @@ -159,7 +159,7 @@ class restorable : public snapshot_interface // Iterator that begins at the end of the stack iterator begin() { return iterator(&_buffer[_pos - 1], _buffer - 1); } - const_iterator begin() const { return iterator(&_buffer[_pos - 1], _buffer - 1); } + const_iterator begin() const { return const_iterator(&_buffer[_pos - 1], _buffer - 1); } // Iterator that points to the element past the beginning of the stack iterator end() { return iterator(_buffer - 1, _buffer - 1); } @@ -198,9 +198,11 @@ class restorable : public snapshot_interface _pos = _jump; // Move over empty data - while (isNull(_buffer[_pos - 1])) + while (_pos > 0 && isNull(_buffer[_pos - 1])) _pos--; + inkAssert(_pos > 0, "Can not pop. No non-null elements to pop!"); + // Decrement and return _pos--; return _buffer[_pos]; @@ -211,10 +213,11 @@ class restorable : public snapshot_interface { inkAssert(_pos > 0, "Can not top. No elememnts to show!"); auto pos = _pos; - if (_pos == _save) + if (pos == _save) pos = _jump; - while (isNull(_buffer[pos - 1])) + while (pos > 0 && isNull(_buffer[pos - 1])) --pos; + inkAssert(pos > 0, "Can not top. No non-null elements to show!"); return _buffer[pos - 1]; } @@ -228,7 +231,7 @@ class restorable : public snapshot_interface // Forward iterate template - void for_each(CallbackMethod callback, IsNullPredicate isNull) + void for_each(CallbackMethod callback, IsNullPredicate isNull) const { if (_pos == 0) { return; diff --git a/inkcpp/list_impl.cpp b/inkcpp/list_impl.cpp index 030c4684..d0e68983 100644 --- a/inkcpp/list_impl.cpp +++ b/inkcpp/list_impl.cpp @@ -40,11 +40,13 @@ void list_impl::next(const char*& flag_name, const char*& list_name, int& i, boo return; } - list_flag flag{static_cast(i >> 16), static_cast(i & 0xFF)}; + list_flag flag{static_cast(i >> 16), static_cast(i & 0x7FFF)}; if (flag_name != nullptr) { ++flag.flag; } - if (static_cast(flag.flag) >= _list_table->_list_end[flag.list_id]) { + if (flag.list_id < 0 || static_cast(flag.list_id) >= _list_table->_list_end.size() + || static_cast(flag.flag) + >= (_list_table->_list_end[flag.list_id] - _list_table->listBegin(flag.list_id))) { next_list: if (one_list_only) { i = -1; @@ -53,7 +55,7 @@ void list_impl::next(const char*& flag_name, const char*& list_name, int& i, boo flag.flag = 0; do { ++flag.list_id; - if (static_cast(flag.list_id) >= _list_table->_list_end.size()) { + if (flag.list_id < 0 || static_cast(flag.list_id) >= _list_table->_list_end.size()) { i = -1; return; } @@ -66,15 +68,24 @@ void list_impl::next(const char*& flag_name, const char*& list_name, int& i, boo goto next_list; } } - flag_name = _list_table->_flag_names[_list_table->toFid(flag)]; - list_name = _list_table->_list_names[flag.list_id]; + int fid = _list_table->toFid(flag); + flag_name = (fid >= 0 && static_cast(fid) < _list_table->_flag_names.size()) + ? _list_table->_flag_names[fid] + : nullptr; + list_name + = (flag.list_id >= 0 && static_cast(flag.list_id) < _list_table->_list_names.size()) + ? _list_table->_list_names[flag.list_id] + : nullptr; - i = (flag.list_id << 16) | flag.flag; + i = (flag.list_id << 16) | (flag.flag & 0x7FFF); } list_interface::iterator list_impl::begin(const char* list_name) const { - size_t list_id = _list_table->get_list_id(list_name).list_id; - return ++new_iterator(nullptr, list_id << 16, true); + list_flag lf = _list_table->get_list_id(list_name); + if (lf.list_id < 0) { + return end(); + } + return ++new_iterator(nullptr, lf.list_id << 16, true); } } // namespace ink::runtime::internal diff --git a/inkcpp/list_operations.h b/inkcpp/list_operations.h index 70798e42..33fa9f51 100644 --- a/inkcpp/list_operations.h +++ b/inkcpp/list_operations.h @@ -332,9 +332,30 @@ class operation void operator()(basic_eval_stack& stack, value* vals) { inkAssert(vals[0].type() == value_type::list_flag, "LIST_VALUE only works on list_flag values"); - stack.push(value{}.set( - static_cast(vals[0].get().flag) + 1 - )); + list_flag flag = vals[0].get(); + if (flag.list_id < 0 || flag.flag < 0) { + stack.push(value{}.set(0)); + } else { + stack.push(value{}.set(_list_table.get_flag_value(flag))); + } + } +}; + +template<> +class operation : public operation_base +{ +public: + using operation_base::operation_base; + + void operator()(basic_eval_stack& stack, value* vals) + { + list_table::list l = vals[0].get(); + list_flag max_flag = _list_table.max(l); + if (max_flag.list_id < 0 || max_flag.flag < 0) { + stack.push(value{}.set(0)); + } else { + stack.push(value{}.set(_list_table.get_flag_value(max_flag))); + } } }; diff --git a/inkcpp/list_table.cpp b/inkcpp/list_table.cpp index b4c2d143..af6df219 100644 --- a/inkcpp/list_table.cpp +++ b/inkcpp/list_table.cpp @@ -153,19 +153,33 @@ void list_table::gc() _list_handouts.clear(); } -size_t list_table::toFid(list_flag e) const { return listBegin(e.list_id) + e.flag; } - -size_t list_table::stringLen(const list_flag& e) const { return c_str_len(toString(e)); } +int list_table::toFid(list_flag e) const +{ + if (e.list_id < 0 || e.flag < 0 || static_cast(e.list_id) >= _list_end.size()) { + return -1; + } + return static_cast(listBegin(static_cast(e.list_id)) + static_cast(e.flag)); +} const char* list_table::toString(const list_flag& e) const { - if (e.list_id < 0 || e.flag < 0) { + int fid = toFid(e); + if (fid < 0 || static_cast(fid) >= _flag_names.size()) { return ""; } - const char* res = _flag_names[toFid(e)]; + const char* res = _flag_names[fid]; return res == nullptr ? "" : res; } +char* list_table::toString(char* out, const list_flag& e) const +{ + const char* str = toString(e); + while (*str) { + *out++ = *str++; + } + return out; +} + size_t list_table::stringLen(const list& l) const { size_t len = 0; @@ -284,10 +298,18 @@ list_table::list list_table::add(list_flag lh, list_flag rh) { list res = create(); data_t* o = getPtr(res.lid); - setList(o, lh.list_id); - setFlag(o, toFid(lh)); - setList(o, rh.list_id); - setFlag(o, toFid(rh)); + if (lh.list_id >= 0) { + setList(o, lh.list_id); + if (lh.flag >= 0) { + setFlag(o, toFid(lh)); + } + } + if (rh.list_id >= 0) { + setList(o, rh.list_id); + if (rh.flag >= 0) { + setFlag(o, toFid(rh)); + } + } return res; } @@ -339,8 +361,12 @@ list_table::list list_table::add(list lh, list_flag rh) for (int i = 0; i < _entrySize; ++i) { o[i] = l[i]; } - setList(o, rh.list_id); - setFlag(o, toFid(rh)); + if (rh.list_id >= 0) { + setList(o, rh.list_id); + if (rh.flag >= 0) { + setFlag(o, toFid(rh)); + } + } return res; } @@ -388,13 +414,16 @@ list_table::list list_table::sub(list lh, list_flag rh) for (int i = 0; i < _entrySize; ++i) { o[i] = l[i]; } + if (rh.list_id < 0 || rh.flag < 0 || static_cast(rh.list_id) >= _list_end.size()) { + return res; + } setFlag(o, toFid(rh), false); for (size_t i = listBegin(rh.list_id); i < _list_end[rh.list_id]; ++i) { if (hasFlag(o, i)) { return res; } } - setList(l, rh.list_id, false); + setList(o, rh.list_id, false); for (size_t i = 0; i < numLists(); ++i) { if (hasList(o, i)) { return res; @@ -406,6 +435,9 @@ list_table::list list_table::sub(list lh, list_flag rh) list_flag list_table::sub(list_flag lh, list rh) { + if (lh.list_id < 0 || lh.flag < 0) { + return lh; + } data_t* r = getPtr(rh.lid); if (hasList(r, lh.list_id) && hasFlag(r, toFid(lh))) { return list_flag{lh.list_id, -1}; @@ -454,13 +486,18 @@ list_table::list list_table::add(list arg, int n) list_flag list_table::add(list_flag arg, int n) { - if (arg == null_flag || arg == empty_flag || arg.flag == -1) { + if (arg == null_flag || arg == empty_flag || arg.flag == -1 || arg.list_id < 0 + || static_cast(arg.list_id) >= _list_end.size()) { return arg; } - int value = _flag_values[arg.flag] + n; + int fid = toFid(arg); + if (fid < 0 || static_cast(fid) >= _flag_values.size()) { + return arg; + } + int value = _flag_values[fid] + n; for (size_t i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { if (_flag_values[i] == value) { - arg.flag = static_cast(i); + arg.flag = static_cast(i - listBegin(arg.list_id)); return arg; } } @@ -510,10 +547,11 @@ list_flag list_table::sub(list_flag arg, int i) { return add(arg, -i); } int32_t list_table::count(list_flag lf) const { - if (lf == empty_flag || lf == null_flag || lf.flag == -1) { + if (lf == empty_flag || lf == null_flag || lf.flag == -1 || lf.list_id < 0) { return 0; } - if (_flag_names[toFid(lf)] == nullptr) { + int fid = toFid(lf); + if (fid < 0 || static_cast(fid) >= _flag_names.size() || _flag_names[fid] == nullptr) { return 0; } return 1; @@ -538,14 +576,18 @@ int32_t list_table::count(list l) const list_flag list_table::min(list l) const { list_flag res{-1, -1}; - const data_t* data = getPtr(l.lid); + int min_val = 0; + bool found = false; + const data_t* data = getPtr(l.lid); for (size_t i = 0; i < numLists(); ++i) { if (hasList(data, i)) { for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(data, j)) { int value = _flag_values[j]; - if (res.flag < 0 || value < res.flag) { - res.flag = static_cast(value); + if (! found || value < min_val) { + found = true; + min_val = value; + res.flag = static_cast(j - listBegin(i)); res.list_id = static_cast(i); } break; @@ -559,14 +601,18 @@ list_flag list_table::min(list l) const list_flag list_table::max(list l) const { list_flag res{-1, -1}; - const data_t* data = getPtr(l.lid); + int max_val = 0; + bool found = false; + const data_t* data = getPtr(l.lid); for (size_t i = 0; i < numLists(); ++i) { if (hasList(data, i)) { for (size_t j = _list_end[i] - 1; j != ~0U && j >= listBegin(i); --j) { if (hasFlag(data, j)) { int value = _flag_values[j]; - if (value > res.flag) { - res.flag = static_cast(value); + if (! found || value > max_val) { + found = true; + max_val = value; + res.flag = static_cast(j - listBegin(i)); res.list_id = static_cast(i); } break; @@ -598,6 +644,12 @@ bool list_table::equal(list lh, list rh) const bool list_table::equal(list lh, list_flag rh) const { + if (rh.list_id < 0 || rh.flag < 0) { + return count(lh) == 0; + } + if (static_cast(rh.list_id) >= _list_end.size()) { + return false; + } const data_t* l = getPtr(lh.lid); for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i) != (rh.list_id == static_cast(i))) { @@ -631,7 +683,8 @@ list_table::list list_table::all(list arg) list_table::list list_table::all(list_flag arg) { list res = create(); - if (arg != null_flag) { + if (arg != null_flag && arg != empty_flag && arg.list_id >= 0 + && static_cast(arg.list_id) < _list_end.size()) { data_t* o = getPtr(res.lid); setList(o, arg.list_id); for (size_t i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { @@ -668,8 +721,10 @@ list_table::list list_table::invert(list arg) list_table::list list_table::invert(list_flag arg) { list res = create(); - if (arg != null_flag) { + if (arg != null_flag && arg != empty_flag && arg.list_id >= 0 + && static_cast(arg.list_id) < _list_end.size()) { data_t* o = getPtr(res.lid); + setList(o, arg.list_id); for (size_t i = listBegin(arg.list_id); i < _list_end[arg.list_id]; ++i) { setFlag(o, i, arg.flag != static_cast(i - listBegin(arg.list_id))); } @@ -691,6 +746,9 @@ list_table::list list_table::intersect(list lh, list rh) list_flag list_table::intersect(list lh, list_flag rh) { + if (rh.list_id < 0 || rh.flag < 0) { + return null_flag; + } const data_t* l = getPtr(lh.lid); if (hasList(l, rh.list_id) && hasFlag(l, toFid(rh))) { return rh; @@ -700,21 +758,27 @@ list_flag list_table::intersect(list lh, list_flag rh) bool list_table::has(list lh, list_flag rh) const { + if (rh.list_id < 0 || rh.flag < 0) { + return false; + } const data_t* l = getPtr(lh.lid); return hasList(l, rh.list_id) && hasFlag(l, toFid(rh)); } list_flag list_table::lrnd(list lh, prng& rng) const { + int n = count(lh); + if (n <= 0) { + return null_flag; + } const data_t* l = getPtr(lh.lid); - int n = count(lh); n = rng.rand(n); - int count = 0; + int count_val = 0; for (size_t i = 0; i < numLists(); ++i) { if (hasList(l, i)) { for (size_t j = listBegin(i); j < _list_end[i]; ++j) { if (hasFlag(l, j)) { - if (count++ == n) { + if (count_val++ == n) { return list_flag{ static_cast(i), static_cast(j - listBegin(i)) @@ -752,8 +816,11 @@ optional list_table::toFlag(const char* flag_name) const const char* periode = str_find(flag_name, '.'); if (periode) { list_flag list = get_list_id(flag_name); // since flag_name is `list_name.flag_name` - flag_name = periode + 1; - int list_begin = list.list_id == 0 ? 0 : _list_end[list.list_id - 1]; + if (list.list_id < 0 || static_cast(list.list_id) >= _list_end.size()) { + return nullopt; + } + flag_name = periode + 1; + size_t list_begin = listBegin(static_cast(list.list_id)); for (size_t i = list_begin; i != _list_end[list.list_id]; ++i) { if (str_equal(flag_name, _flag_names[i])) { return { @@ -793,7 +860,6 @@ list_flag list_table::get_list_id(const char* list_name) const return list_flag{i, -1}; } } - inkAssert(false, "No list with name found!"); return null_flag; } diff --git a/inkcpp/list_table.h b/inkcpp/list_table.h index 62a8715e..05d0e610 100644 --- a/inkcpp/list_table.h +++ b/inkcpp/list_table.h @@ -78,7 +78,10 @@ class list_table : public snapshot_interface flag.flag = -1; return flag; } - inkAssert(flag.list_id >= 0, "expected flag to have a base list."); + if (flag.list_id < 0 || static_cast(flag.list_id) >= _list_end.size()) { + flag.flag = -1; + return flag; + } for (size_t i = listBegin(static_cast(flag.list_id)); i < _list_end[static_cast(flag.list_id)]; ++i) { if (_flag_values[i] == flag.flag) { @@ -92,12 +95,15 @@ class list_table : public snapshot_interface int get_flag_value(list_flag flag) const { - inkAssert( - flag.list_id >= 0 && flag.flag >= 0, - "flag is not an valid flag (expeted list and flag in list)" - ); - return _flag_values - [listBegin(static_cast(flag.list_id)) + static_cast(flag.flag)]; + if (flag.list_id < 0 || flag.flag < 0 + || static_cast(flag.list_id) >= _list_end.size()) { + return 0; + } + size_t fid = listBegin(static_cast(flag.list_id)) + static_cast(flag.flag); + if (fid >= _flag_values.size()) { + return 0; + } + return _flag_values[fid]; } /// zeros all usage values @@ -136,8 +142,17 @@ class list_table : public snapshot_interface { } - size_t stringLen(const list_flag& e) const; + size_t stringLen(const list_flag& e) const + { + int fid = toFid(e); + if (fid < 0 || static_cast(fid) >= _flag_names.size() || _flag_names[fid] == nullptr) { + return 0; + } + return c_str_len(_flag_names[fid]); + } + const char* toString(const list_flag& e) const; + char* toString(char* out, const list_flag& e) const; /** returns len of string representation of list */ size_t stringLen(const list& l) const; @@ -225,13 +240,37 @@ class list_table : public snapshot_interface template bool less(L lh, R rh) const { - return max(lh).flag < min(rh).flag; + list_flag mlh = max(lh); + list_flag mrh = min(rh); + const bool lh_empty = mlh.list_id < 0 || mlh.flag < 0; + const bool rh_empty = mrh.list_id < 0 || mrh.flag < 0; + // nothing is smaller than an empty list + if (rh_empty) { + return false; + } + // an empty list is always smaller than a non-empty + if (lh_empty) { + return true; + } + return get_flag_value(mlh) < get_flag_value(mrh); } template bool greater(L lh, R rh) const { - return min(lh).flag > max(rh).flag; + list_flag mlh = min(lh); + list_flag mrh = max(rh); + const bool lh_empty = mlh.list_id < 0 || mlh.flag < 0; + const bool rh_empty = mrh.list_id < 0 || mrh.flag < 0; + // an empty list is bigger then nothing + if (lh_empty) { + return false; + } + // a non-empty list is always greater than an empty one if (Rh_empty) { + if (rh_empty) { + return true; + } + return get_flag_value(mlh) > get_flag_value(mrh); } bool equal(list lh, list rh) const; @@ -244,19 +283,49 @@ class list_table : public snapshot_interface template bool not_equal(L lh, R rh) const { - return equal(lh, rh); + return ! equal(lh, rh); } template bool greater_equal(L lh, R rh) const { - return max(lh).flag >= max(rh).flag && min(lh).flag >= min(rh).flag; + list_flag max_l = max(lh), max_r = max(rh); + list_flag min_l = min(lh), min_r = min(rh); + const bool lh_empty + = max_l.list_id < 0 || max_l.flag < 0 || min_l.list_id < 0 || min_l.flag < 0; + const bool rh_empty + = max_r.list_id < 0 || max_r.flag < 0 || min_r.list_id < 0 || min_r.flag < 0; + // everything is geared equal an empty list + if (rh_empty) { + return true; + } + // only an empty list is equal an empty list (already checked above) + if (lh_empty) { + return false; + } + return get_flag_value(max_l) >= get_flag_value(max_r) + && get_flag_value(min_l) >= get_flag_value(min_r); } template bool less_equal(L lh, R rh) const { - return max(lh).flag <= max(rh).flag && min(lh).flag <= min(rh).flag; + list_flag max_l = max(lh), max_r = max(rh); + list_flag min_l = min(lh), min_r = min(rh); + const bool lh_empty + = max_l.list_id < 0 || max_l.flag < 0 || min_l.list_id < 0 || min_l.flag < 0; + const bool rh_empty + = max_r.list_id < 0 || max_r.flag < 0 || min_r.list_id < 0 || min_r.flag < 0; + // an empty list is less or equal to every other list + if (lh_empty) { + return true; + } + // a non-empty list is always bigger then an empty one + if (rh_empty) { + return false; + } + return get_flag_value(max_l) <= get_flag_value(max_r) + && get_flag_value(min_l) <= get_flag_value(min_r); } bool has(list lh, list rh) const; @@ -297,7 +366,10 @@ class list_table : public snapshot_interface size_t listBegin(size_t lid) const { - return lid == 0 ? 0 : _list_end[static_cast(lid - 1)]; + if (lid == 0 || lid > _list_end.size()) { + return 0; + } + return _list_end[static_cast(lid - 1)]; } const data_t* getPtr(int eid) const @@ -335,7 +407,7 @@ class list_table : public snapshot_interface bool hasList(const data_t* data, int lid) const { - if (lid < 0) { + if (lid < 0 || static_cast(lid) >= numLists()) { return false; } return getBit(data, static_cast(lid)); @@ -343,14 +415,14 @@ class list_table : public snapshot_interface void setList(data_t* data, int lid, bool value = true) { - if (lid >= 0) { + if (lid >= 0 && static_cast(lid) < numLists()) { setBit(data, static_cast(lid), value); } } bool hasFlag(const data_t* data, int fid) const { - if (fid < 0) { + if (fid < 0 || static_cast(fid) >= numFlags()) { return false; } return getBit(data, static_cast(fid) + numLists()); @@ -358,12 +430,12 @@ class list_table : public snapshot_interface void setFlag(data_t* data, int fid, bool value = true) { - if (fid >= 0) { + if (fid >= 0 && static_cast(fid) < numFlags()) { setBit(data, static_cast(fid) + numLists(), value); } } - size_t toFid(list_flag e) const; + int toFid(list_flag e) const; auto flagStartMask() const { @@ -433,16 +505,21 @@ class list_table : public snapshot_interface if (_pos.flag.flag < 0 || _pos.flag.list_id < 0) { return; } - if (static_cast(_pos.flag.flag) - == _list._list_end[static_cast(_pos.flag.list_id)] - - _list.listBegin(static_cast(_pos.flag.list_id))) { + while (static_cast(_pos.flag.list_id) < _list.numLists() + && static_cast(_pos.flag.flag) + >= _list._list_end[static_cast(_pos.flag.list_id)] + - _list.listBegin(static_cast(_pos.flag.list_id))) { _pos.flag.flag = 0; ++_pos.flag.list_id; } - if (static_cast(_pos.flag.list_id) == _list.numLists()) { + if (static_cast(_pos.flag.list_id) >= _list.numLists()) { _pos.flag = null_flag; + _pos.name = nullptr; } else { - _pos.name = _list._flag_names[_list.toFid(_pos.flag)]; + int fid = _list.toFid(_pos.flag); + _pos.name = (fid >= 0 && static_cast(fid) < _list._flag_names.size()) + ? _list._flag_names[fid] + : nullptr; } } @@ -450,17 +527,19 @@ class list_table : public snapshot_interface { bool valid; do { - valid = true; - size_t fid = _list.toFid(_pos.flag); + valid = true; + int fid = _list.toFid(_pos.flag); if (_data == nullptr) { - if (_list._flag_names[fid] == nullptr) { + if (fid < 0 || static_cast(fid) >= _list._flag_names.size() + || _list._flag_names[fid] == nullptr) { valid = false; ++_pos.flag.flag; } } else if (! _list.hasList(_data, _pos.flag.list_id)) { valid = false; ++_pos.flag.list_id; - } else if (! _list.hasFlag(_data, static_cast(fid)) + } else if (fid < 0 || ! _list.hasFlag(_data, fid) + || static_cast(fid) >= _list._flag_names.size() || _list._flag_names[fid] == nullptr) { valid = false; ++_pos.flag.flag; diff --git a/inkcpp/simple_restorable_stack.h b/inkcpp/simple_restorable_stack.h index db7f5138..81913238 100644 --- a/inkcpp/simple_restorable_stack.h +++ b/inkcpp/simple_restorable_stack.h @@ -44,6 +44,7 @@ class simple_restorable_stack : public snapshot_interface bool iter(const T*& iterator) const; bool rev_iter(const T*& iterator) const; + // == Save/Restore == bool is_saved() const { return _save != InvalidIndex; } diff --git a/inkcpp/stack.cpp b/inkcpp/stack.cpp index 3be83512..3da5c07c 100644 --- a/inkcpp/stack.cpp +++ b/inkcpp/stack.cpp @@ -183,10 +183,7 @@ void basic_stack::push_frame(offset_t return_to, bool eval) add(InvalidHash, value{}.set(return_to, eval)); } -const entry* basic_stack::pop() -{ - return &base::pop([](const entry& elem) { return elem.name == ~0U; }); -} +const entry* basic_stack::pop() { return &base::pop(is_entry_null); } entry* basic_stack::do_thread_jump_pop(const basic_stack::iterator& jumpStart) { @@ -237,9 +234,9 @@ entry* basic_stack::do_thread_jump_pop(const basic_stack::iterator& jumpStart) start.set(jump); } else if (vt == value_type::thread_start) { start.set(jump); - } else { - inkFail("unknown jump type"); } + + // Return pointer to frame marker return threadIter.get(); } @@ -258,35 +255,29 @@ offset_t basic_stack::pop_frame(frame_type* type, bool& eval) inkAssert(! base::is_empty(), "Can not pop frame from empty callstack."); const entry* returnedFrame = nullptr; - auto isNull = [](const entry& e) { - return e.name == ~0U; - }; // Start iterating backwards iterator iter = base::begin(); - if (isNull(*iter.get())) { - iter.next(isNull); + if (is_entry_null(*iter.get())) { + iter.next(is_entry_null); } while (! iter.done()) { // Keep popping if it's not a frame marker or thread marker of some kind entry* frame = iter.get(); - if (frame->name != InvalidHash) { + if (frame->name != InvalidHash || frame->data.type() == value_type::none) { pop(); iter = base::begin(); - if (isNull(*iter.get())) { - iter.next(isNull); + if (is_entry_null(*iter.get())) { + iter.next(is_entry_null); } continue; } // We now have a frame marker. Check if it's a thread // Thread handling - if ( - // FIXME: is_tghead_marker, is_jump_marker - frame->data.type() == value_type::thread_start + if (frame->data.type() == value_type::thread_start || frame->data.type() == value_type::thread_end - || frame->data.type() == value_type::jump_marker - ) { + || frame->data.type() == value_type::jump_marker) { // End of thread marker, we need to create a jump marker if (frame->data.type() == value_type::thread_end) { // Push a new jump marker after the thread end diff --git a/inkcpp/stack.h b/inkcpp/stack.h index 5b383baf..2d87e8a9 100644 --- a/inkcpp/stack.h +++ b/inkcpp/stack.h @@ -31,6 +31,11 @@ namespace runtime thread }; + inline bool is_entry_null(const entry& e) + { + return e.name == ~0U || (e.name == InvalidHash && e.data.type() == value_type::none); + } + class basic_stack : protected restorable { friend list_table; @@ -54,6 +59,20 @@ namespace runtime value* get(hash_t name); value* get_from_frame(int ci, hash_t name); +#ifdef INK_ENABLE_STL + void print_dump(std::ostream& out) const + { + out << "DUMPING STACK:\n"; + int idx = 0; + auto it = this->begin(); + while (! it.done()) { + out << " [" << idx++ << "] hash " << it.get()->name << " type " + << static_cast(it.get()->data.type()) << "\n"; + it.next(); + } + } +#endif + // pushes a new frame onto the stack // @param eval if evaluation mode was active template diff --git a/inkcpp_compiler/binary_emitter.cpp b/inkcpp_compiler/binary_emitter.cpp index 8523ecd2..1a13f53a 100644 --- a/inkcpp_compiler/binary_emitter.cpp +++ b/inkcpp_compiler/binary_emitter.cpp @@ -523,8 +523,8 @@ void binary_emitter::set_list_meta(const list_data& list_defs) _list_meta.write('\0'); } _list_meta.write( - reinterpret_cast(flag.name->c_str()), - static_cast(flag.name->size()) + 1 + reinterpret_cast(flag.name.c_str()), + static_cast(flag.name.size()) + 1 ); } _list_meta.write(null_flag); diff --git a/inkcpp_compiler/list_data.cpp b/inkcpp_compiler/list_data.cpp index 8f9905c3..50046d5b 100644 --- a/inkcpp_compiler/list_data.cpp +++ b/inkcpp_compiler/list_data.cpp @@ -28,7 +28,7 @@ void list_data::new_flag(const std::string& flag_name, int value) ); _list_end.back() += 1; _flags.emplace_back( - &flag_name, + flag_name, list_flag{ static_cast(_list_name.size() - 1), static_cast(value) diff --git a/inkcpp_compiler/list_data.h b/inkcpp_compiler/list_data.h index 0df93c53..e195bece 100644 --- a/inkcpp_compiler/list_data.h +++ b/inkcpp_compiler/list_data.h @@ -39,14 +39,14 @@ class list_data bool empty() const { return _lists.empty(); } struct named_list_flag { - named_list_flag(const std::string* name, list_flag flag) - : name{name} + named_list_flag(std::string name, list_flag flag) + : name{std::move(name)} , flag{flag} { } - const std::string* name; - list_flag flag; + std::string name; + list_flag flag; bool operator<(const named_list_flag& oth) const { @@ -59,11 +59,11 @@ class list_data const std::vector& get_flags() const { return _flags; } - const std::vector& get_list_names() const { return _list_name; } + const std::vector& get_list_names() const { return _list_name; } private: std::map> _lists; - std::vector _list_name; + std::vector _list_name; std::vector _list_end; std::vector _flags; };