diff --git a/furvm/include/furvm/module.hpp b/furvm/include/furvm/module.hpp index 4fb6a9f..5a8cab9 100644 --- a/furvm/include/furvm/module.hpp +++ b/furvm/include/furvm/module.hpp @@ -27,6 +27,10 @@ struct mod_type { std::size_t size; }; + struct slice_value { + mod_type_id typeId; + }; + struct import_value { mod_id modId; mod_type_id typeId; @@ -44,6 +48,7 @@ struct mod_type { Ptr, Ref, Array, + Slice, Import, Count, @@ -52,6 +57,7 @@ struct mod_type { std::nullptr_t null = nullptr; mod_type_id typeRef; array_value array; + slice_value slice; import_value imprt; value() = default; @@ -96,6 +102,7 @@ struct mod_type { ~mod_type() { switch (type) { case Array: value.array.~array_value(); break; + case Slice: value.slice.~slice_value(); break; case Import: value.imprt.~import_value(); break; default: break; } @@ -105,6 +112,7 @@ struct mod_type { : type(other.type) { switch (type) { case Array: new (&value.array) array_value(other.value.array); break; + case Slice: new (&value.slice) slice_value(other.value.slice); break; case Import: new (&value.imprt) import_value(std::move(other.value.imprt)); break; default: break; } @@ -116,6 +124,7 @@ struct mod_type { type = other.type; switch (type) { case Array: new (&value.array) array_value(other.value.array); break; + case Slice: new (&value.slice) slice_value(other.value.slice); break; case Import: new (&value.imprt) import_value(std::move(other.value.imprt)); break; default: break; } @@ -127,6 +136,7 @@ struct mod_type { : type(other.type) { switch (type) { case Array: new (&value.array) array_value(other.value.array); break; + case Slice: new (&value.slice) slice_value(other.value.slice); break; case Import: new (&value.imprt) import_value(other.value.imprt); break; default: break; } @@ -137,6 +147,7 @@ struct mod_type { type = other.type; switch (type) { case Array: new (&value.array) array_value(other.value.array); break; + case Slice: new (&value.slice) slice_value(other.value.slice); break; case Import: new (&value.imprt) import_value(other.value.imprt); break; default: break; } diff --git a/furvm/include/furvm/thing.hpp b/furvm/include/furvm/thing.hpp index 2778f64..142ae19 100644 --- a/furvm/include/furvm/thing.hpp +++ b/furvm/include/furvm/thing.hpp @@ -35,6 +35,10 @@ struct thing_type { std::size_t size; }; + struct slice_value { + thing_type* type; + }; + enum type { // NOLINT S8 = 0, S16, @@ -47,6 +51,7 @@ struct thing_type { Ptr, Ref, Array, + Slice, Count, } type = Count; @@ -54,6 +59,7 @@ struct thing_type { std::nullptr_t null = nullptr; thing_type* typeRef; array_value array; + slice_value slice; value() = default; @@ -85,6 +91,7 @@ struct thing_type { case Ptr: case Ref: return *value.typeRef == *other.value.typeRef; case Array: return *value.array.type == *other.value.array.type && value.array.size == other.value.array.size; + case Slice: return *value.slice.type == *other.value.slice.type; case Count: break; } return false; @@ -104,7 +111,8 @@ struct thing_type { case U64: return true; case Ptr: case Ref: - case Array: return false; + case Array: + case Slice: return false; case Count: break; } throw std::runtime_error("unreachable"); @@ -122,7 +130,8 @@ struct thing_type { case thing_type::U64: return sizeof(u64); case Ptr: case Ref: - case Array: return 0; + case Array: + case Slice: return 0; case Count: break; } throw std::runtime_error("unreachable"); @@ -150,6 +159,7 @@ struct thing_type_hash { seed = furlang::utility::hash_combine(seed, std::hash{}(type.value.array.size)); return seed; + case thing_type::Slice: return furlang::utility::hash_combine(seed, thing_type_hash{}(*type.value.slice.type)); case thing_type::Count: break; } throw std::runtime_error("unreachable"); @@ -205,6 +215,11 @@ public: std::byte* data; }; + struct slice { + std::size_t length; + std::byte* data; + }; + struct header { thing_type type; }; @@ -363,7 +378,8 @@ private: case thing_type::U16: case thing_type::U32: case thing_type::U64: - case thing_type::Ptr: std::memcpy(dst.m_data, m_data, m_size); return; + case thing_type::Ptr: + case thing_type::Slice: std::memcpy(dst.m_data, m_data, m_size); return; case thing_type::Array: copy_list(*m_type, dst.m_data, m_data); return; case thing_type::Ref: // TODO: Implement arrays of references (I think they're possible). case thing_type::Count: break; @@ -551,31 +567,69 @@ public: } thing at(thing_type::u64 index) const { - if (!is(thing_type::Array)) throw bad_thing_access(); - thing ref = { m_allocator }; ref.m_reference = true; - ref.m_size = compute_size_na(*type().value.array.type); + ref.m_size = compute_size_na(*(ref.m_type = &inner_type())); - if (type().value.array.size == 0) { - auto& array = get(); - if (index < 0 || index >= array.size) throw std::out_of_range("index out of range"); + switch (type().type) { + case thing_type::Array: { + if (type().value.array.size == 0) { + auto& array = get(); + if (index < 0 || index >= array.size) throw std::out_of_range("index out of range"); - ref.m_type = type().value.array.type; - ref.m_data = array.data + (index * ref.m_size); + ref.m_data = array.data + (index * ref.m_size); + return ref; + } + + if (index < 0 || index >= type().value.array.size) throw std::out_of_range("index out of range"); + ref.m_data = m_data + (index * ref.m_size); return ref; } + case thing_type::Slice: { + const auto& slice = get(); + if (index < 0 || index >= slice.length) throw std::out_of_range("index out of range"); + ref.m_data = slice.data + (index * ref.m_size); + return ref; + } + default: throw bad_thing_access(); + } + } - if (index < 0 || index >= type().value.array.size) throw std::out_of_range("index out of range"); + thing slice(thing_type::u64 begin, thing_type::u64 len) const { + auto& inner = inner_type(); - ref.m_type = type().value.array.type; - ref.m_data = m_data + (index * ref.m_size); - return ref; + thing_type sliceType; + sliceType.type = thing_type::Slice; + sliceType.value.slice.type = &inner; + + thing slice = { sliceType, m_allocator }; + auto& data = slice.get(); + + if (begin >= length()) throw std::out_of_range("begin index out of range"); + len = std::min(len, length() - begin); + + switch (type().type) { + case thing_type::Array: { + data.data = ((type().value.array.size != 0) ? m_data : get().data) ; + } break; + case thing_type::Slice: { + data.data = get().data ; + } break; + default: throw bad_thing_access(); + } + + data.data += (compute_size_na(inner) * begin); + data.length = len; + return slice; } thing_type::u64 length() const { - if (!is(thing_type::Array)) throw bad_thing_access(); - return type().value.array.size == 0 ? get().size : type().value.array.size; + switch (type().type) { + case thing_type::Array: + return type().value.array.size == 0 ? get().size : type().value.array.size; + case thing_type::Slice: return get().length; + default: throw bad_thing_access(); + } } template >> @@ -603,7 +657,8 @@ public: case thing_type::U64: std::memcpy(m_data, rhs.m_data, m_size); return; case thing_type::Ptr: case thing_type::Ref: - case thing_type::Array: throw std::runtime_error("unimplemented"); + case thing_type::Array: + case thing_type::Slice: throw std::runtime_error("unimplemented"); case thing_type::Count: break; } throw std::runtime_error("unreachable"); @@ -643,7 +698,8 @@ private: case thing_type::U32: case thing_type::U64: case thing_type::Ptr: - case thing_type::Ref: std::memcpy(dst, src, size * elementSize); return; + case thing_type::Ref: + case thing_type::Slice: std::memcpy(dst, src, size * elementSize); return; case thing_type::Array: for (std::size_t i = 0; i < size; ++i) { copy_list(*innerType.value.array.type, @@ -670,6 +726,7 @@ private: case thing_type::Array: return type.value.array.size == 0 ? sizeof(dynamic_array) : compute_size_na(*type.value.array.type) * type.value.array.size; + case thing_type::Slice: return sizeof(struct slice); case thing_type::Ref: case thing_type::Count: break; } @@ -804,6 +861,7 @@ private: case thing_type::Ptr: // TODO: Pointer arithmetics case thing_type::Ref: case thing_type::Array: + case thing_type::Slice: case thing_type::Count: break; } throw std::runtime_error("unreachable"); @@ -828,6 +886,14 @@ private: m_data = nullptr; m_type = nullptr; } + + thing_type& inner_type() const { + switch (type().type) { + case thing_type::Array: return *type().value.array.type; + case thing_type::Slice: return *type().value.slice.type; + default: throw bad_thing_access(); + } + } private: // A flag indicating whether the thing instance owns the data, or not. bool m_reference = false; diff --git a/furvm/src/main.cpp b/furvm/src/main.cpp index 91accef..591aa46 100644 --- a/furvm/src/main.cpp +++ b/furvm/src/main.cpp @@ -30,6 +30,14 @@ static void print_thing(const furvm::thing<>& thing) { } std::cout << " }"; break; + case thing_type::Slice: + std::cout << "Slice [" << thing.length() << "] { "; + for (thing_type::u64 i = 0; i < thing.length(); ++i) { + if (i > 0) std::cout << ", "; + print_thing(thing.at(i)); + } + std::cout << " }"; + break; default: std::cerr << "{Type not recognized}"; } } diff --git a/furvm/src/module.cpp b/furvm/src/module.cpp index 9005201..6b94d02 100644 --- a/furvm/src/module.cpp +++ b/furvm/src/module.cpp @@ -54,6 +54,9 @@ std::ostream& mod::serialize(std::ostream& os) const { detail::serialize(os, type.value.array.typeId); detail::serialize(os, type.value.array.size); } break; + case mod_type::Slice: { + detail::serialize(os, type.value.slice.typeId); + } break; case mod_type::Import: { detail::serialize(os, type.value.imprt.modId); detail::serialize(os, type.value.imprt.typeId); @@ -169,6 +172,11 @@ mod mod::load(std::istream& is) { detail::load(is, size); mod.emplace_type(id, typeId, size).dispatch(); } break; + case mod_type::Slice: { + mod_type_id typeId = 0; + detail::load(is, typeId); + mod.emplace_type(id, mod_type::Slice, typeId).dispatch(); + } break; case mod_type::Import: { std::string modName; detail::load(is, modName);