refactor(furvm): improve thing value access
This commit is contained in:
@@ -96,11 +96,17 @@ public:
|
|||||||
struct dynamic_array {
|
struct dynamic_array {
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
std::byte* data;
|
std::byte* data;
|
||||||
|
|
||||||
|
static bool matches(const thing_type& type) {
|
||||||
|
return type.type == thing_type::Array && type.value.array.size == 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct slice {
|
struct slice {
|
||||||
std::size_t length;
|
std::size_t length;
|
||||||
std::byte* data;
|
std::byte* data;
|
||||||
|
|
||||||
|
static bool matches(const thing_type& type) { return type.type == thing_type::Slice; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct header {
|
struct header {
|
||||||
@@ -407,7 +413,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T& get() {
|
T& get() {
|
||||||
if (compute_size_na(*m_type) != sizeof(T)) throw bad_thing_access();
|
if (!detail::thing_traits<T>{}(*m_type)) throw bad_thing_access();
|
||||||
return *std::launder(reinterpret_cast<T*>(m_data));
|
return *std::launder(reinterpret_cast<T*>(m_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +424,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T& get() const {
|
const T& get() const {
|
||||||
if (compute_size_na(*m_type) != sizeof(T)) throw bad_thing_access();
|
if (!detail::thing_traits<T>{}(*m_type)) throw bad_thing_access();
|
||||||
return *std::launder(reinterpret_cast<const T*>(m_data));
|
return *std::launder(reinterpret_cast<const T*>(m_data));
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace furvm {
|
namespace furvm {
|
||||||
|
|
||||||
@@ -127,6 +129,76 @@ struct thing_type {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct overrides_thing_type_matching : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct overrides_thing_type_matching<T, std::void_t<decltype(T::matches(std::declval<const thing_type&>()))>>
|
||||||
|
: std::is_same<decltype(T::matches(std::declval<const thing_type&>())), bool> {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct thing_traits {
|
||||||
|
bool operator()(const thing_type& type) const {
|
||||||
|
if constexpr (overrides_thing_type_matching<T>::value) {
|
||||||
|
return T::matches(type);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<s8> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::S8; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<u8> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::U8; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<s16> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::S16; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<u16> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::U16; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<s32> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::S32; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<u32> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::U32; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<s64> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::S64; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct thing_traits<u64> {
|
||||||
|
bool operator()(const thing_type& type) const { return type.type == thing_type::U64; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Inner>
|
||||||
|
struct thing_traits<Inner*> {
|
||||||
|
bool operator()(const thing_type& type) const {
|
||||||
|
return (type.type == thing_type::Ptr || type.type == thing_type::Ref) &&
|
||||||
|
thing_traits<Inner>{}(*type.value.typeRef);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
} // namespace furvm
|
} // namespace furvm
|
||||||
|
|
||||||
#endif // FURVM_TYPES_HPP
|
#endif // FURVM_TYPES_HPP
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "furvm/exceptions.hpp"
|
||||||
#include "furvm/furvm.hpp"
|
#include "furvm/furvm.hpp"
|
||||||
#include "furvm/thing.hpp"
|
#include "furvm/thing.hpp"
|
||||||
|
|
||||||
@@ -77,4 +78,12 @@ TEST(ThingOps, Iterators) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ThingOps, Access) {
|
||||||
|
furvm::thing thing{ furvm::thing_type{ furvm::thing_type::U8 } };
|
||||||
|
EXPECT_NO_THROW(thing.get<furvm::u8>());
|
||||||
|
EXPECT_THROW(thing.get<furvm::s8>(), furvm::bad_thing_access);
|
||||||
|
EXPECT_THROW(thing.get<furvm::s32>(), furvm::bad_thing_access);
|
||||||
|
EXPECT_THROW(thing.get<void*>(), furvm::bad_thing_access);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user