//------------------------------------------------------------------------------------------------------------------------------------------------------------- // // 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)); } //-------------------------------------------------------------------------------------------------------------------------------------------------------------