Skip to content

Commit

Permalink
Unified Type Traits
Browse files Browse the repository at this point in the history
  • Loading branch information
potatomashed committed Oct 5, 2024
1 parent fc5c790 commit 2da2e0b
Show file tree
Hide file tree
Showing 29 changed files with 778 additions and 752 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.15)

project(
mlc
VERSION 0.0.5
DESCRIPTION "PyMLC"
VERSION 0.0.6
DESCRIPTION "MLC-Python"
LANGUAGES C CXX
)

Expand Down
10 changes: 1 addition & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@ pip install -U mlc-python

TBA

**Configuration Tool.** PyMLC provides LLVM-style configuration tools for compiling and linking.

```
>>> mlc.config --includedir --libdir
/home/user/Projects/pymlc/.venv/lib/python3.12/site-packages/include;/home/user/Projects/pymlc/.venv/lib/python3.12/site-packages/3rdparty/dlpack/include
/home/user/Projects/pymlc/.venv/lib/python3.12/site-packages/mlc/lib
```

## Development

### Build from Source
Expand All @@ -32,7 +24,7 @@ pre-commit install

### Create Wheels

See `.github/workflows/wheels.yml` for more details. PyMLC uses `cibuildwheel` to build cross-platform wheels.
See `.github/workflows/wheels.yml` for more details. This project uses `cibuildwheel` to build cross-platform wheels.

```bash
export CIBW_BUILD_VERBOSITY=3
Expand Down
1 change: 1 addition & 0 deletions cpp/c_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,5 @@ MLC_API void MLCExtObjDelete(void *objptr) {
::mlc::base::DecRef(ptr);
}
}
delete[] reinterpret_cast<char *>(objptr);
}
48 changes: 26 additions & 22 deletions cpp/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,16 @@ struct TypeInfoWrapper {
template <typename T> struct PODGetterSetter {
static int32_t Getter(MLCTypeField *, void *addr, MLCAny *ret) {
using namespace ::mlc::base;
PODTraits<T>::TypeCopyToAny(*static_cast<T *>(addr), ret);
TypeTraits<T>::TypeToAny(*static_cast<T *>(addr), ret);
return 0;
}
static int32_t Setter(MLCTypeField *, void *addr, MLCAny *src) {
using namespace mlc::base;
try {
*static_cast<T *>(addr) = PODTraits<T>::AnyCopyToType(src);
*static_cast<T *>(addr) = TypeTraits<T>::AnyToTypeUnowned(src);
} catch (const TemporaryTypeError &) {
std::ostringstream oss;
oss << "Cannot convert from type `" << TypeIndex2TypeKey(src->type_index) << "` to `" << PODTraits<T>::Type2Str()
oss << "Cannot convert from type `" << TypeIndex2TypeKey(src->type_index) << "` to `" << TypeTraits<T>::type_str
<< "`";
*static_cast<::mlc::Any *>(src) = MLC_MAKE_ERROR_HERE(TypeError, oss.str());
return -2;
Expand Down Expand Up @@ -324,24 +324,29 @@ struct TypeTable {
};

struct _POD_REG {
inline static const int32_t _none = base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCNone))
.MemFn("__str__", &base::PODTraits<std::nullptr_t>::__str__);
inline static const int32_t _int = base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCInt))
.MemFn("__str__", &base::PODTraits<int64_t>::__str__);
inline static const int32_t _float = base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCFloat))
.MemFn("__str__", &base::PODTraits<double>::__str__);
inline static const int32_t _ptr = base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCPtr))
.MemFn("__str__", &base::PODTraits<void *>::__str__);
inline static const int32_t _device =
base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCDevice))
inline static const int32_t _none = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCNone))
.MemFn("__str__", &::mlc::base::TypeTraits<std::nullptr_t>::__str__);
inline static const int32_t _int = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCInt))
.MemFn("__str__", &::mlc::base::TypeTraits<int64_t>::__str__);
inline static const int32_t _float = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCFloat))
.MemFn("__str__", &::mlc::base::TypeTraits<double>::__str__);
inline static const int32_t _ptr = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCPtr))
.MemFn("__str__", &::mlc::base::TypeTraits<void *>::__str__);
inline static const int32_t _device = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCDevice))
.StaticFn("__init__", [](AnyView device) { return device.operator DLDevice(); })
.MemFn("__str__", &base::PODTraits<DLDevice>::__str__);
inline static const int32_t _dtype =
base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCDataType))
.MemFn("__str__", &::mlc::base::TypeTraits<DLDevice>::__str__);
inline static const int32_t _dtype = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCDataType))
.StaticFn("__init__", [](AnyView dtype) { return dtype.operator DLDataType(); })
.MemFn("__str__", &base::PODTraits<DLDataType>::__str__);
inline static const int32_t _str = base::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCRawStr))
.MemFn("__str__", &base::PODTraits<const char *>::__str__);
.MemFn("__str__", &::mlc::base::TypeTraits<DLDataType>::__str__);
inline static const int32_t _str = //
::mlc::core::ReflectionHelper(static_cast<int32_t>(MLCTypeIndex::kMLCRawStr))
.MemFn("__str__", &::mlc::base::TypeTraits<const char *>::__str__);
};

inline TypeTable *TypeTable::New() {
Expand All @@ -351,12 +356,11 @@ inline TypeTable *TypeTable::New() {
self->num_types = static_cast<int32_t>(MLCTypeIndex::kMLCDynObjectBegin);
#define MLC_TYPE_TABLE_INIT_TYPE(UnderlyingType, Self) \
{ \
MLCTypeInfo *info = Self->TypeRegister(-1, ::mlc::base::PODTraits<UnderlyingType>::default_type_index, \
::mlc::base::PODTraits<UnderlyingType>::Type2Str()); \
MLCTypeInfo *info = Self->TypeRegister(-1, ::mlc::base::TypeTraits<UnderlyingType>::default_type_index, \
::mlc::base::TypeTraits<UnderlyingType>::type_str); \
info->setter = PODGetterSetter<UnderlyingType>::Setter; \
info->getter = PODGetterSetter<UnderlyingType>::Getter; \
}

MLC_TYPE_TABLE_INIT_TYPE(std::nullptr_t, self);
MLC_TYPE_TABLE_INIT_TYPE(int64_t, self);
MLC_TYPE_TABLE_INIT_TYPE(double, self);
Expand Down
216 changes: 93 additions & 123 deletions include/mlc/base/all.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,23 @@
#include "./traits_scalar.h"
#include "./traits_str.h"
#include <cstring>
#include <vector>

/*********** AnyView ***********/

namespace mlc {

/*********** Section 1. Any <=> Any View ***********/
MLC_INLINE AnyView::AnyView(const Any &src) : MLCAny(static_cast<const MLCAny &>(src)) {}
MLC_INLINE AnyView::AnyView(Any &&src) : MLCAny(static_cast<const MLCAny &>(src)) {}
MLC_INLINE Any::Any(const Any &src) : MLCAny(static_cast<const MLCAny &>(src)) { this->IncRef(); }
MLC_INLINE Any::Any(Any &&src) : MLCAny(static_cast<const MLCAny &>(src)) { *static_cast<MLCAny *>(&src) = MLCAny(); }
MLC_INLINE Any::Any(const AnyView &src) : MLCAny(static_cast<const MLCAny &>(src)) {
this->SwitchFromRawStr();
this->IncRef();
}
MLC_INLINE Any::Any(AnyView &&src) : MLCAny(static_cast<const MLCAny &>(src)) {
*static_cast<MLCAny *>(&src) = MLCAny();
this->SwitchFromRawStr();
this->IncRef();
}
MLC_INLINE AnyView &AnyView::operator=(const Any &src) {
*static_cast<MLCAny *>(this) = static_cast<const MLCAny &>(src);
return *this;
Expand All @@ -24,149 +34,109 @@ MLC_INLINE AnyView &AnyView::operator=(Any &&src) {
*static_cast<MLCAny *>(this) = static_cast<const MLCAny &>(src);
return *this;
}
MLC_INLINE AnyView::AnyView(::mlc::base::tag::ObjPtr, const MLCObjPtr &src) : MLCAny() {
if (src.ptr != nullptr) {
this->type_index = src.ptr->type_index;
this->v_obj = src.ptr;
}
}
MLC_INLINE AnyView::AnyView(::mlc::base::tag::ObjPtr, MLCObjPtr &&src) : MLCAny() {
if (src.ptr != nullptr) {
this->type_index = src.ptr->type_index;
this->v_obj = src.ptr;
}
MLC_INLINE Any &Any::operator=(const Any &src) {
Any(src).Swap(*this);
return *this;
}
template <typename T> MLC_INLINE AnyView::AnyView(::mlc::base::tag::POD, const T &src) : MLCAny() {
::mlc::base::PODTraits<::mlc::base::RemoveCR<T>>::TypeCopyToAny(src, this);
MLC_INLINE Any &Any::operator=(Any &&src) {
Any(std::move(src)).Swap(*this);
return *this;
}
template <typename T> MLC_INLINE AnyView::AnyView(::mlc::base::tag::POD, T &&src) : MLCAny() {
::mlc::base::PODTraits<::mlc::base::RemoveCR<T>>::TypeCopyToAny(src, this);
MLC_INLINE Any &Any::operator=(const AnyView &src) {
Any(src).Swap(*this);
return *this;
}
template <typename T> MLC_INLINE AnyView::AnyView(::mlc::base::tag::RawObjPtr, T *src) : MLCAny() {
::mlc::base::PtrToAnyView<T>(src, this);
MLC_INLINE Any &Any::operator=(AnyView &&src) {
Any(std::move(src)).Swap(*this);
return *this;
}
template <typename T> MLC_INLINE T AnyView::Cast(::mlc::base::tag::ObjPtr) const {
if constexpr (::mlc::base::IsObjRef<T>) {
if (this->type_index == static_cast<int32_t>(MLCTypeIndex::kMLCNone)) {
using RefT = Ref<typename T::TObj>;
MLC_THROW(TypeError) << "Cannot convert from type `None` to non-nullable `" << ::mlc::base::Type2Str<RefT>::Run()
<< "`";
}
}
using TObj = typename T::TObj;
return T([this]() -> TObj * {
MLC_TRY_CONVERT(::mlc::base::ObjPtrTraits<TObj>::AnyToOwnedPtr(this), this->type_index,
::mlc::base::Type2Str<TObj *>::Run());
}());
}
template <typename T> MLC_INLINE T AnyView::Cast() const {
if constexpr (std::is_same_v<T, Any> || std::is_same_v<T, AnyView>) {
return *this;

/*********** Section 2. Conversion between Any/AnyView <=> POD ***********/

template <typename T> MLC_INLINE AnyView::AnyView(const T &src) : MLCAny() {
using namespace ::mlc::base;
if constexpr (HasTypeTraits<T>) {
TypeTraits<T>::TypeToAny(src, this);
} else {
return this->operator T();
(src.operator AnyView()).Swap(*this);
}
}
template <typename T> MLC_INLINE_NO_MSVC T AnyView::Cast(::mlc::base::tag::POD) const {
MLC_TRY_CONVERT(::mlc::base::PODTraits<::mlc::base::RemoveCR<T>>::AnyCopyToType(this), this->type_index,
::mlc::base::Type2Str<T>::Run());
}
template <typename _T> MLC_INLINE_NO_MSVC _T AnyView::Cast(::mlc::base::tag::RawObjPtr) const {
using T = std::remove_pointer_t<_T>;
MLC_TRY_CONVERT(::mlc::base::ObjPtrTraits<::mlc::base::RemoveCR<T>>::AnyToUnownedPtr(this), this->type_index,
::mlc::base::Type2Str<T *>::Run());
}
template <typename T> MLC_INLINE_NO_MSVC T *AnyView::CastWithStorage(Any *storage) const {
MLC_TRY_CONVERT(::mlc::base::ObjPtrTraits<T>::AnyToOwnedPtrWithStorage(this, storage), this->type_index,
::mlc::base::Type2Str<T *>::Run());
}
} // namespace mlc

/*********** Any ***********/

namespace mlc {
MLC_INLINE Any::Any(::mlc::base::tag::ObjPtr, const MLCObjPtr &src) : MLCAny() {
if (src.ptr != nullptr) {
this->type_index = src.ptr->type_index;
this->v_obj = src.ptr;
template <typename T> MLC_INLINE Any::Any(const T &src) : MLCAny() {
using namespace ::mlc::base;
if constexpr (HasTypeTraits<RemoveCR<T>>) {
TypeTraits<RemoveCR<T>>::TypeToAny(src, this);
this->SwitchFromRawStr();
this->IncRef();
} else {
(src.operator Any()).Swap(*this);
}
}
MLC_INLINE Any::Any(::mlc::base::tag::ObjPtr, MLCObjPtr &&src) : MLCAny() {
if (src.ptr != nullptr) {
this->type_index = src.ptr->type_index;
this->v_obj = src.ptr;
src.ptr = nullptr;
}
}
template <typename T> MLC_INLINE Any::Any(::mlc::base::tag::RawObjPtr, T *src) : MLCAny() {
::mlc::base::PtrToAnyView<T>(src, this);
this->IncRef();
}
template <typename T> MLC_INLINE T Any::Cast() const {
if constexpr (std::is_same_v<T, Any> || std::is_same_v<T, AnyView>) {
return *this;

template <typename T> MLC_INLINE_NO_MSVC T AnyView::Cast() const {
using namespace ::mlc::base;
if constexpr (HasTypeTraits<T>) {
MLC_TRY_CONVERT(TypeTraits<T>::AnyToTypeUnowned(this), this->type_index, Type2Str<T>::Run());
} else {
return this->operator T();
return T(*this);
}
}
template <typename T> MLC_INLINE T Any::Cast(::mlc::base::tag::ObjPtr) const {
if constexpr (::mlc::base::IsObjRef<T>) {
if (this->type_index == static_cast<int32_t>(MLCTypeIndex::kMLCNone)) {
using RefT = Ref<typename T::TObj>;
MLC_THROW(TypeError) << "Cannot convert from type `None` to non-nullable `" << ::mlc::base::Type2Str<RefT>::Run()
<< "`";
}

template <typename T> MLC_INLINE_NO_MSVC T Any::Cast() const {
using namespace ::mlc::base;
if constexpr (HasTypeTraits<T>) {
MLC_TRY_CONVERT(TypeTraits<T>::AnyToTypeUnowned(this), this->type_index, Type2Str<T>::Run());
} else {
return T(*this);
}
using TObj = typename T::TObj;
return T([this]() -> TObj * {
MLC_TRY_CONVERT(::mlc::base::ObjPtrTraits<TObj>::AnyToOwnedPtr(this), this->type_index,
::mlc::base::Type2Str<TObj *>::Run());
}());
}
template <typename T> MLC_INLINE_NO_MSVC T Any::Cast(::mlc::base::tag::POD) const {
MLC_TRY_CONVERT(::mlc::base::PODTraits<::mlc::base::RemoveCR<T>>::AnyCopyToType(this), this->type_index,
::mlc::base::Type2Str<T>::Run());
}
template <typename _T> MLC_INLINE_NO_MSVC _T Any::Cast(::mlc::base::tag::RawObjPtr) const {
using T = std::remove_pointer_t<_T>;
MLC_TRY_CONVERT(::mlc::base::ObjPtrTraits<::mlc::base::RemoveCR<T>>::AnyToUnownedPtr(this), this->type_index,
::mlc::base::Type2Str<T *>::Run());

template <typename T> MLC_INLINE_NO_MSVC T AnyView::CastWithStorage(Any *storage) const {
using namespace ::mlc::base;
MLC_TRY_CONVERT(TypeTraits<T>::AnyToTypeWithStorage(this, storage), this->type_index, Type2Str<T>::Run());
}
template <typename T> MLC_INLINE_NO_MSVC T *Any::CastWithStorage(Any *storage) const {
MLC_TRY_CONVERT(::mlc::base::ObjPtrTraits<T>::AnyToOwnedPtrWithStorage(this, storage), this->type_index,
::mlc::base::Type2Str<T *>::Run());

template <typename T> MLC_INLINE_NO_MSVC T Any::CastWithStorage(Any *storage) const {
using namespace ::mlc::base;
MLC_TRY_CONVERT(TypeTraits<T>::AnyToTypeWithStorage(this, storage), this->type_index, Type2Str<T>::Run());
}
} // namespace mlc

namespace mlc {
namespace base {
struct ReflectionHelper {
explicit ReflectionHelper(int32_t type_index);
template <typename Super, typename FieldType>
ReflectionHelper &FieldReadOnly(const char *name, FieldType Super::*field);
template <typename Super, typename FieldType> ReflectionHelper &Field(const char *name, FieldType Super::*field);
template <typename Callable> ReflectionHelper &MemFn(const char *name, Callable &&method);
template <typename Callable> ReflectionHelper &StaticFn(const char *name, Callable &&method);
operator int32_t();
static std::string DefaultStrMethod(AnyView any);
/*********** Section 3. Conversion between Any/AnyView <=> Ref ***********/

private:
template <typename Cls, typename FieldType> constexpr std::ptrdiff_t ReflectOffset(FieldType Cls::*member) {
return reinterpret_cast<std::ptrdiff_t>(&((Cls *)(nullptr)->*member));
template <typename T> MLC_INLINE Ref<T>::Ref(const AnyView &src) : TBase() { TBase::_Init<T>(src); }
template <typename T> MLC_INLINE Ref<T>::Ref(const Any &src) : TBase() { TBase::_Init<T>(src); }
template <typename T> MLC_INLINE Ref<T>::operator AnyView() const {
if (this->ptr != nullptr) {
AnyView ret;
ret.type_index = this->ptr->type_index;
ret.v_obj = this->ptr;
return ret;
}
template <typename Super, typename FieldType> MLCTypeField PrepareField(const char *name, FieldType Super::*field);
template <typename Callable> MLCTypeMethod PrepareMethod(const char *name, Callable &&method);
return AnyView();
}
template <typename T> MLC_INLINE Ref<T>::operator Any() const & {
if (this->ptr != nullptr) {
Any ret;
ret.type_index = this->ptr->type_index;
ret.v_obj = this->ptr;
::mlc::base::IncRef(this->ptr);
return ret;
}
return Any();
}
template <typename T> MLC_INLINE Ref<T>::operator Any() && {
if (this->ptr != nullptr) {
Any ret;
ret.type_index = this->ptr->type_index;
ret.v_obj = this->ptr;
this->ptr = nullptr;
return ret;
}
return Any();
}

int32_t type_index;
std::vector<MLCTypeField> fields;
std::vector<MLCTypeMethod> methods;
std::vector<Any> method_pool;
std::vector<std::vector<MLCTypeInfo *>> type_annotation_pool;
};
} // namespace base
} // namespace mlc
/*********** Section 4. AnyViewArray ***********/

namespace mlc {
template <std::size_t N> template <typename... Args> MLC_INLINE void AnyViewArray<N>::Fill(Args &&...args) {
static_assert(sizeof...(args) == N, "Invalid number of arguments");
if constexpr (N > 0) {
Expand Down
Loading

0 comments on commit 2da2e0b

Please sign in to comment.