Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Type API to mitigate issues around memory #427

Merged
merged 16 commits into from
Aug 6, 2022
Merged
54 changes: 42 additions & 12 deletions cpp/include/mun/error.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef MUN_ERROR_H_
#define MUN_ERROR_H_

#include <optional>
#include <string_view>

#include "mun/runtime_capi.h"

namespace mun {
Expand All @@ -11,45 +14,72 @@ namespace mun {
class Error {
public:
/** Default constructs an error. */
Error() noexcept : m_handle{nullptr} {}
constexpr Error() noexcept : m_handle{nullptr} {}

/** Constructs an error from a `MunErrorHandle`.
*
* \param handle an error handle
* \param handle an error type_handle
*/
Error(MunErrorHandle handle) noexcept : m_handle(handle) {}
constexpr Error(MunErrorHandle handle) noexcept : m_handle(handle) {}

/** Move constructs an error.
*
* \param other an rvalue reference to an error
*/
Error(Error&& other) noexcept : m_handle(other.m_handle) { other.m_handle._0 = nullptr; }
constexpr Error(Error&& other) noexcept : m_handle(other.m_handle) {
other.m_handle.error_string = nullptr;
}

/** Move assigns an error.
*
* \param other an rvalue reference to an error
*/
Error& operator=(Error&& other) noexcept {
constexpr Error& operator=(Error&& other) noexcept {
m_handle = other.m_handle;
other.m_handle._0 = nullptr;
other.m_handle.error_string = nullptr;
return *this;
}

/** Destructs the error. */
~Error() noexcept { mun_error_destroy(m_handle); }

/** Returns the error message, if it exists, otherwise returns a nullptr.
*
* The message is UTF-8 encoded.
/**
* Returns the error message, if it exists, otherwise returns `std::nullopt`. The message is
* UTF-8 encoded.
*/
[[nodiscard]] constexpr std::optional<std::string_view> message() const noexcept {
if (m_handle.error_string != nullptr) return std::make_optional(m_handle.error_string);
return std::nullopt;
}

/**
* Returns true if this instance contains an error message. False if the result is Ok.
*/
const char* message() noexcept { return m_handle._0; }
[[nodiscard]] constexpr inline bool is_error() const {
return m_handle.error_string != nullptr;
}

/** Retrieves whether an error occurred */
operator bool() const noexcept { return m_handle._0 != nullptr; }
/**
* Returns true if this instance represents an OK result.
*/
[[nodiscard]] constexpr inline bool is_ok() const { return m_handle.error_string == nullptr; }

private:
MunErrorHandle m_handle;
};
} // namespace mun

#ifdef NDEBUG
#define MUN_ASSERT(expr) ((void)expr)
#else
#define MUN_ASSERT(expr) \
do { \
::mun::Error err(expr); \
if (auto message = err.message(); message) { \
std::cerr << "Assertion Error: " #expr " failed: " << message.value(); \
std::abort(); \
} \
} while (0)
#endif

#endif
120 changes: 90 additions & 30 deletions cpp/include/mun/field_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,88 +4,148 @@
#include <cassert>

#include "mun/runtime_capi.h"
#include "mun/type_info.h"
#include "mun/type.h"

namespace mun {
/**
* @brief A wrapper around a Mun field information handle.
* @brief A wrapper around a MunField.
*
* The Type from which this Field came must be kept alive during the lifetime of this instance.
*/
class FieldInfo {
public:
/**
* @brief Constructs field information from an instantiated `MunFieldInfoHandle`.
*/
FieldInfo(MunFieldInfoHandle handle) noexcept : m_handle(handle) {}
constexpr explicit FieldInfo(MunField handle) noexcept : m_handle(handle) {}

/**
* @brief Retrieves the field's name.
*/
std::string_view name() const noexcept {
const auto ptr = mun_field_info_name(m_handle);
assert(ptr);
return ptr;
[[nodiscard]] std::string name() const noexcept {
const char* name;
MUN_ASSERT(mun_field_name(m_handle, &name));
std::string str(name);
mun_string_destroy(name);
return str;
}

/**
* @brief Retrieves the field's type.
*/
TypeInfo type() const noexcept {
const auto type_handle = mun_field_info_type(m_handle);
assert(type_handle._0);
return TypeInfo(type_handle);
[[nodiscard]] Type type() const noexcept {
MunType ty;
MUN_ASSERT(mun_field_type(m_handle, &ty));
return Type(ty);
}

/**
* @brief Retrieves the field's offset.
*/
uint16_t offset() const noexcept {
uint16_t offset;
const auto error_handle = mun_field_info_offset(m_handle, &offset);
assert(error_handle._0 == nullptr);
[[nodiscard]] uintptr_t offset() const noexcept {
uintptr_t offset;
MUN_ASSERT(mun_field_offset(m_handle, &offset));
return offset;
}

private:
MunFieldInfoHandle m_handle;
MunField m_handle;
};

/**
* @brief A wrapper around a span of Mun field informations, which are owned by the Mun runtime.
* @brief A wrapper around MunTypes. Stores field information of a struct.
*
* Note that the StructType must not go out of scope or undefined behavior can occur.
*/
class FieldInfoSpan {
class StructFields {
public:
struct Iterator {
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = FieldInfo;

constexpr explicit Iterator(MunField const* ptr) : m_ptr(ptr){};

value_type operator*() const { return value_type(*m_ptr); }

Iterator& operator++() {
m_ptr++;
return *this;
}

Iterator operator++(int) {
Iterator tmp = *this;
++(*this);
return tmp;
}

friend bool operator==(const Iterator& a, const Iterator& b) { return a.m_ptr == b.m_ptr; };
friend bool operator!=(const Iterator& a, const Iterator& b) { return a.m_ptr != b.m_ptr; };

private:
MunField const* m_ptr;
};

/**
* @brief Constructs a field information span from an instantiated `MunFieldInfoSpan`.
* @brief Constructs a field information span from an instantiated `MunTypes`.
*
* This function assumes ownership is transferred.
*/
FieldInfoSpan(MunFieldInfoSpan span) noexcept : m_span(span) {}
constexpr explicit StructFields(MunFields fields) noexcept : m_data(fields) {}

FieldInfoSpan(FieldInfoSpan&&) = default;
FieldInfoSpan(const FieldInfoSpan&) = delete;
constexpr StructFields(StructFields&& other) noexcept : m_data(other.m_data) {
other.m_data.fields = nullptr;
}
StructFields(const StructFields&) = delete;

~StructFields() noexcept {
if (m_data.fields != nullptr) {
mun_fields_destroy(m_data);
m_data.fields = nullptr;
}
}

~FieldInfoSpan() noexcept { mun_field_info_span_destroy(m_span); }
StructFields& operator=(const StructFields&) = delete;
StructFields& operator=(StructFields&& other) noexcept {
std::swap(m_data, other.m_data);
return *this;
}

/**
* @brief Returns an iterator to the beginning.
*/
const MunFieldInfoHandle* begin() const noexcept { return data(); }
[[nodiscard]] inline constexpr Iterator begin() const noexcept {
return Iterator(m_data.fields);
}

/**
* @brief Returns an iterator to the end.
*/
const MunFieldInfoHandle* end() const noexcept { return data() + size() + 1; }
[[nodiscard]] inline constexpr Iterator end() const noexcept {
return Iterator(m_data.fields + m_data.count);
}

/**
* @brief Returns a pointer to the beginning of the sequence of elements.
* Finds a certain field by its name.
*/
const MunFieldInfoHandle* data() const noexcept { return m_span.data; }
[[nodiscard]] std::optional<FieldInfo> find_by_name(std::string_view name) const {
MunField field;
bool has_field;
MUN_ASSERT(mun_fields_find_by_name(m_data, name.data(), name.size(), &has_field, &field));
if (has_field) {
return std::make_optional(FieldInfo(field));
} else {
return std::nullopt;
}
}

/**
* @brief Returns the number of elements in the sequence.
* @brief Returns the number of fields.
*/
size_t size() const noexcept { return m_span.len; }
[[nodiscard]] inline size_t size() const noexcept { return m_data.count; }

private:
MunFieldInfoSpan m_span;
MunFields m_data;
};
} // namespace mun

Expand Down
87 changes: 87 additions & 0 deletions cpp/include/mun/function.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifndef MUN_FUNCTION_INFO_H_
#define MUN_FUNCTION_INFO_H_

#include <cassert>

#include "mun/runtime_capi.h"
#include "mun/type.h"

namespace mun {
/**
* @brief A wrapper around a Mun function handle.
*/
class Function {
public:
/**
* @brief Constructs type information from a MunFunction handle.
*
* This function assumes that ownership is transferred.
*/
constexpr explicit Function(MunFunction handle) noexcept : m_handle(handle) {}

Function(const Function& other) : m_handle(other.m_handle) {
MUN_ASSERT(mun_function_add_reference(m_handle));
}
constexpr Function(Function&& other) : m_handle(other.m_handle) { other.m_handle._0 = nullptr; }

~Function() {
if (m_handle._0 != nullptr) {
MUN_ASSERT(mun_function_release(m_handle));
m_handle._0 = nullptr;
}
}

Function& operator=(const Function& other) {
if (other.m_handle._0 != nullptr) {
MUN_ASSERT(mun_function_add_reference(other.m_handle));
}
if (m_handle._0 != nullptr) {
MUN_ASSERT(mun_function_release(m_handle));
}
m_handle = other.m_handle;
}

/**
* @brief Retrieves the function's name.
*/
[[nodiscard]] std::string name() const noexcept {
const char* name;
MUN_ASSERT(mun_function_name(m_handle, &name));
std::string name_str(name);
mun_string_destroy(name);
return name_str;
}

/**
* @brief Retrieves the function's argument types.
*/
[[nodiscard]] TypeArray argument_types() const noexcept {
MunTypes types;
MUN_ASSERT(mun_function_argument_types(m_handle, &types));
return TypeArray(types);
}

/**
* @brief Retrieves the function's return type.
*/
[[nodiscard]] Type return_type() const noexcept {
MunType handle;
MUN_ASSERT(mun_function_return_type(m_handle, &handle));
return Type(handle);
}

/**
* @brief Retrieves the function's pointer.
*/
[[nodiscard]] const void* function_pointer() const noexcept {
const void* ptr;
MUN_ASSERT(mun_function_fn_ptr(m_handle, &ptr));
return ptr;
}

private:
MunFunction m_handle;
};
} // namespace mun

#endif // MUN_FUNCTION_INFO_H_
Loading