mirror of https://git.suyu.dev/suyu/suyu
303 lines
11 KiB
C++
303 lines
11 KiB
C++
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Foundation/NSObject.hpp
|
|
//
|
|
// Copyright 2020-2023 Apple Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
#include "NSDefines.hpp"
|
|
#include "NSPrivate.hpp"
|
|
#include "NSTypes.hpp"
|
|
|
|
#include <objc/message.h>
|
|
#include <objc/runtime.h>
|
|
|
|
#include <type_traits>
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
namespace NS
|
|
{
|
|
template <class _Class, class _Base = class Object>
|
|
class _NS_EXPORT Referencing : public _Base
|
|
{
|
|
public:
|
|
_Class* retain();
|
|
void release();
|
|
|
|
_Class* autorelease();
|
|
|
|
UInteger retainCount() const;
|
|
};
|
|
|
|
template <class _Class, class _Base = class Object>
|
|
class Copying : public Referencing<_Class, _Base>
|
|
{
|
|
public:
|
|
_Class* copy() const;
|
|
};
|
|
|
|
template <class _Class, class _Base = class Object>
|
|
class SecureCoding : public Referencing<_Class, _Base>
|
|
{
|
|
};
|
|
|
|
class Object : public Referencing<Object, objc_object>
|
|
{
|
|
public:
|
|
UInteger hash() const;
|
|
bool isEqual(const Object* pObject) const;
|
|
|
|
class String* description() const;
|
|
class String* debugDescription() const;
|
|
|
|
protected:
|
|
friend class Referencing<Object, objc_object>;
|
|
|
|
template <class _Class>
|
|
static _Class* alloc(const char* pClassName);
|
|
template <class _Class>
|
|
static _Class* alloc(const void* pClass);
|
|
template <class _Class>
|
|
_Class* init();
|
|
|
|
template <class _Dst>
|
|
static _Dst bridgingCast(const void* pObj);
|
|
static class MethodSignature* methodSignatureForSelector(const void* pObj, SEL selector);
|
|
static bool respondsToSelector(const void* pObj, SEL selector);
|
|
template <typename _Type>
|
|
static constexpr bool doesRequireMsgSendStret();
|
|
template <typename _Ret, typename... _Args>
|
|
static _Ret sendMessage(const void* pObj, SEL selector, _Args... args);
|
|
template <typename _Ret, typename... _Args>
|
|
static _Ret sendMessageSafe(const void* pObj, SEL selector, _Args... args);
|
|
|
|
private:
|
|
Object() = delete;
|
|
Object(const Object&) = delete;
|
|
~Object() = delete;
|
|
|
|
Object& operator=(const Object&) = delete;
|
|
};
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class, class _Base /* = Object */>
|
|
_NS_INLINE _Class* NS::Referencing<_Class, _Base>::retain()
|
|
{
|
|
return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(retain));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class, class _Base /* = Object */>
|
|
_NS_INLINE void NS::Referencing<_Class, _Base>::release()
|
|
{
|
|
Object::sendMessage<void>(this, _NS_PRIVATE_SEL(release));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class, class _Base /* = Object */>
|
|
_NS_INLINE _Class* NS::Referencing<_Class, _Base>::autorelease()
|
|
{
|
|
return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(autorelease));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class, class _Base /* = Object */>
|
|
_NS_INLINE NS::UInteger NS::Referencing<_Class, _Base>::retainCount() const
|
|
{
|
|
return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(retainCount));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class, class _Base /* = Object */>
|
|
_NS_INLINE _Class* NS::Copying<_Class, _Base>::copy() const
|
|
{
|
|
return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(copy));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Dst>
|
|
_NS_INLINE _Dst NS::Object::bridgingCast(const void* pObj)
|
|
{
|
|
#ifdef __OBJC__
|
|
return (__bridge _Dst)pObj;
|
|
#else
|
|
return (_Dst)pObj;
|
|
#endif // __OBJC__
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <typename _Type>
|
|
_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret()
|
|
{
|
|
#if (defined(__i386__) || defined(__x86_64__))
|
|
constexpr size_t kStructLimit = (sizeof(std::uintptr_t) << 1);
|
|
|
|
return sizeof(_Type) > kStructLimit;
|
|
#elif defined(__arm64__)
|
|
return false;
|
|
#elif defined(__arm__)
|
|
constexpr size_t kStructLimit = sizeof(std::uintptr_t);
|
|
|
|
return std::is_class(_Type) && (sizeof(_Type) > kStructLimit);
|
|
#else
|
|
#error "Unsupported architecture!"
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <>
|
|
_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret<void>()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <typename _Ret, typename... _Args>
|
|
_NS_INLINE _Ret NS::Object::sendMessage(const void* pObj, SEL selector, _Args... args)
|
|
{
|
|
#if (defined(__i386__) || defined(__x86_64__))
|
|
if constexpr (std::is_floating_point<_Ret>())
|
|
{
|
|
using SendMessageProcFpret = _Ret (*)(const void*, SEL, _Args...);
|
|
|
|
const SendMessageProcFpret pProc = reinterpret_cast<SendMessageProcFpret>(&objc_msgSend_fpret);
|
|
|
|
return (*pProc)(pObj, selector, args...);
|
|
}
|
|
else
|
|
#endif // ( defined( __i386__ ) || defined( __x86_64__ ) )
|
|
#if !defined(__arm64__)
|
|
if constexpr (doesRequireMsgSendStret<_Ret>())
|
|
{
|
|
using SendMessageProcStret = void (*)(_Ret*, const void*, SEL, _Args...);
|
|
|
|
const SendMessageProcStret pProc = reinterpret_cast<SendMessageProcStret>(&objc_msgSend_stret);
|
|
_Ret ret;
|
|
|
|
(*pProc)(&ret, pObj, selector, args...);
|
|
|
|
return ret;
|
|
}
|
|
else
|
|
#endif // !defined( __arm64__ )
|
|
{
|
|
using SendMessageProc = _Ret (*)(const void*, SEL, _Args...);
|
|
|
|
const SendMessageProc pProc = reinterpret_cast<SendMessageProc>(&objc_msgSend);
|
|
|
|
return (*pProc)(pObj, selector, args...);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
_NS_INLINE NS::MethodSignature* NS::Object::methodSignatureForSelector(const void* pObj, SEL selector)
|
|
{
|
|
return sendMessage<MethodSignature*>(pObj, _NS_PRIVATE_SEL(methodSignatureForSelector_), selector);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
_NS_INLINE bool NS::Object::respondsToSelector(const void* pObj, SEL selector)
|
|
{
|
|
return sendMessage<bool>(pObj, _NS_PRIVATE_SEL(respondsToSelector_), selector);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <typename _Ret, typename... _Args>
|
|
_NS_INLINE _Ret NS::Object::sendMessageSafe(const void* pObj, SEL selector, _Args... args)
|
|
{
|
|
if ((respondsToSelector(pObj, selector)) || (nullptr != methodSignatureForSelector(pObj, selector)))
|
|
{
|
|
return sendMessage<_Ret>(pObj, selector, args...);
|
|
}
|
|
|
|
if constexpr (!std::is_void<_Ret>::value)
|
|
{
|
|
return _Ret(0);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class>
|
|
_NS_INLINE _Class* NS::Object::alloc(const char* pClassName)
|
|
{
|
|
return sendMessage<_Class*>(objc_lookUpClass(pClassName), _NS_PRIVATE_SEL(alloc));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class>
|
|
_NS_INLINE _Class* NS::Object::alloc(const void* pClass)
|
|
{
|
|
return sendMessage<_Class*>(pClass, _NS_PRIVATE_SEL(alloc));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
template <class _Class>
|
|
_NS_INLINE _Class* NS::Object::init()
|
|
{
|
|
return sendMessage<_Class*>(this, _NS_PRIVATE_SEL(init));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
_NS_INLINE NS::UInteger NS::Object::hash() const
|
|
{
|
|
return sendMessage<UInteger>(this, _NS_PRIVATE_SEL(hash));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
_NS_INLINE bool NS::Object::isEqual(const Object* pObject) const
|
|
{
|
|
return sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqual_), pObject);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
_NS_INLINE NS::String* NS::Object::description() const
|
|
{
|
|
return sendMessage<String*>(this, _NS_PRIVATE_SEL(description));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
_NS_INLINE NS::String* NS::Object::debugDescription() const
|
|
{
|
|
return sendMessageSafe<String*>(this, _NS_PRIVATE_SEL(debugDescription));
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------------------------------------
|