Path: blob/master/thirdparty/metal-cpp/Foundation/NSObject.hpp
21066 views
//-------------------------------------------------------------------------------------------------------------------------------------------------------------1//2// Foundation/NSObject.hpp3//4// Copyright 2020-2024 Apple Inc.5//6// Licensed under the Apache License, Version 2.0 (the "License");7// you may not use this file except in compliance with the License.8// You may obtain a copy of the License at9//10// http://www.apache.org/licenses/LICENSE-2.011//12// Unless required by applicable law or agreed to in writing, software13// distributed under the License is distributed on an "AS IS" BASIS,14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.15// See the License for the specific language governing permissions and16// limitations under the License.17//18//-------------------------------------------------------------------------------------------------------------------------------------------------------------1920#pragma once2122//-------------------------------------------------------------------------------------------------------------------------------------------------------------2324#include "NSDefines.hpp"25#include "NSPrivate.hpp"26#include "NSTypes.hpp"2728#include <objc/message.h>29#include <objc/runtime.h>3031#include <type_traits>3233//-------------------------------------------------------------------------------------------------------------------------------------------------------------3435namespace NS36{37class String;3839template <class _Class, class _Base = class Object>40class _NS_EXPORT Referencing : public _Base41{42public:43_Class* retain();44void release();4546_Class* autorelease();4748UInteger retainCount() const;49};5051template <class _Class, class _Base = class Object>52class Copying : public Referencing<_Class, _Base>53{54public:55_Class* copy() const;56};5758template <class _Class, class _Base = class Object>59class SecureCoding : public Referencing<_Class, _Base>60{61};6263class Object : public Referencing<Object, objc_object>64{65public:66UInteger hash() const;67bool isEqual(const Object* pObject) const;6869class String* description() const;70class String* debugDescription() const;7172protected:73friend class Referencing<Object, objc_object>;7475template <class _Class>76static _Class* alloc(const char* pClassName);77template <class _Class>78static _Class* alloc(const void* pClass);79template <class _Class>80_Class* init();8182template <class _Dst>83static _Dst bridgingCast(const void* pObj);84static class MethodSignature* methodSignatureForSelector(const void* pObj, SEL selector);85static bool respondsToSelector(const void* pObj, SEL selector);86template <typename _Type>87static constexpr bool doesRequireMsgSendStret();88template <typename _Ret, typename... _Args>89static _Ret sendMessage(const void* pObj, SEL selector, _Args... args);90template <typename _Ret, typename... _Args>91static _Ret sendMessageSafe(const void* pObj, SEL selector, _Args... args);9293private:94Object() = delete;95Object(const Object&) = delete;96~Object() = delete;9798Object& operator=(const Object&) = delete;99};100}101102//-------------------------------------------------------------------------------------------------------------------------------------------------------------103104template <class _Class, class _Base /* = Object */>105_NS_INLINE _Class* NS::Referencing<_Class, _Base>::retain()106{107return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(retain));108}109110//-------------------------------------------------------------------------------------------------------------------------------------------------------------111112template <class _Class, class _Base /* = Object */>113_NS_INLINE void NS::Referencing<_Class, _Base>::release()114{115Object::sendMessage<void>(this, _NS_PRIVATE_SEL(release));116}117118//-------------------------------------------------------------------------------------------------------------------------------------------------------------119120template <class _Class, class _Base /* = Object */>121_NS_INLINE _Class* NS::Referencing<_Class, _Base>::autorelease()122{123return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(autorelease));124}125126//-------------------------------------------------------------------------------------------------------------------------------------------------------------127128template <class _Class, class _Base /* = Object */>129_NS_INLINE NS::UInteger NS::Referencing<_Class, _Base>::retainCount() const130{131return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(retainCount));132}133134//-------------------------------------------------------------------------------------------------------------------------------------------------------------135136template <class _Class, class _Base /* = Object */>137_NS_INLINE _Class* NS::Copying<_Class, _Base>::copy() const138{139return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(copy));140}141142//-------------------------------------------------------------------------------------------------------------------------------------------------------------143144template <class _Dst>145_NS_INLINE _Dst NS::Object::bridgingCast(const void* pObj)146{147#ifdef __OBJC__148return (__bridge _Dst)pObj;149#else150return (_Dst)pObj;151#endif // __OBJC__152}153154//-------------------------------------------------------------------------------------------------------------------------------------------------------------155156template <typename _Type>157_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret()158{159#if (defined(__i386__) || defined(__x86_64__))160constexpr size_t kStructLimit = (sizeof(std::uintptr_t) << 1);161162return sizeof(_Type) > kStructLimit;163#elif defined(__arm64__)164return false;165#elif defined(__arm__)166constexpr size_t kStructLimit = sizeof(std::uintptr_t);167168return std::is_class_v<_Type> && (sizeof(_Type) > kStructLimit);169#else170#error "Unsupported architecture!"171#endif172}173174//-------------------------------------------------------------------------------------------------------------------------------------------------------------175176template <>177_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret<void>()178{179return false;180}181182//-------------------------------------------------------------------------------------------------------------------------------------------------------------183184template <typename _Ret, typename... _Args>185_NS_INLINE _Ret NS::Object::sendMessage(const void* pObj, SEL selector, _Args... args)186{187#if (defined(__i386__) || defined(__x86_64__))188if constexpr (std::is_floating_point<_Ret>())189{190using SendMessageProcFpret = _Ret (*)(const void*, SEL, _Args...);191192const SendMessageProcFpret pProc = reinterpret_cast<SendMessageProcFpret>(&objc_msgSend_fpret);193194return (*pProc)(pObj, selector, args...);195}196else197#endif // ( defined( __i386__ ) || defined( __x86_64__ ) )198#if !defined(__arm64__)199if constexpr (doesRequireMsgSendStret<_Ret>())200{201using SendMessageProcStret = void (*)(_Ret*, const void*, SEL, _Args...);202203const SendMessageProcStret pProc = reinterpret_cast<SendMessageProcStret>(&objc_msgSend_stret);204_Ret ret;205206(*pProc)(&ret, pObj, selector, args...);207208return ret;209}210else211#endif // !defined( __arm64__ )212{213using SendMessageProc = _Ret (*)(const void*, SEL, _Args...);214215const SendMessageProc pProc = reinterpret_cast<SendMessageProc>(&objc_msgSend);216217return (*pProc)(pObj, selector, args...);218}219}220221//-------------------------------------------------------------------------------------------------------------------------------------------------------------222223_NS_INLINE NS::MethodSignature* NS::Object::methodSignatureForSelector(const void* pObj, SEL selector)224{225return sendMessage<MethodSignature*>(pObj, _NS_PRIVATE_SEL(methodSignatureForSelector_), selector);226}227228//-------------------------------------------------------------------------------------------------------------------------------------------------------------229230_NS_INLINE bool NS::Object::respondsToSelector(const void* pObj, SEL selector)231{232return sendMessage<bool>(pObj, _NS_PRIVATE_SEL(respondsToSelector_), selector);233}234235//-------------------------------------------------------------------------------------------------------------------------------------------------------------236237template <typename _Ret, typename... _Args>238_NS_INLINE _Ret NS::Object::sendMessageSafe(const void* pObj, SEL selector, _Args... args)239{240if ((respondsToSelector(pObj, selector)) || (nullptr != methodSignatureForSelector(pObj, selector)))241{242return sendMessage<_Ret>(pObj, selector, args...);243}244245if constexpr (!std::is_void<_Ret>::value)246{247return _Ret(0);248}249}250251//-------------------------------------------------------------------------------------------------------------------------------------------------------------252253template <class _Class>254_NS_INLINE _Class* NS::Object::alloc(const char* pClassName)255{256return sendMessage<_Class*>(objc_lookUpClass(pClassName), _NS_PRIVATE_SEL(alloc));257}258259//-------------------------------------------------------------------------------------------------------------------------------------------------------------260261template <class _Class>262_NS_INLINE _Class* NS::Object::alloc(const void* pClass)263{264return sendMessage<_Class*>(pClass, _NS_PRIVATE_SEL(alloc));265}266267//-------------------------------------------------------------------------------------------------------------------------------------------------------------268269template <class _Class>270_NS_INLINE _Class* NS::Object::init()271{272return sendMessage<_Class*>(this, _NS_PRIVATE_SEL(init));273}274275//-------------------------------------------------------------------------------------------------------------------------------------------------------------276277_NS_INLINE NS::UInteger NS::Object::hash() const278{279return sendMessage<UInteger>(this, _NS_PRIVATE_SEL(hash));280}281282//-------------------------------------------------------------------------------------------------------------------------------------------------------------283284_NS_INLINE bool NS::Object::isEqual(const Object* pObject) const285{286return sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqual_), pObject);287}288289//-------------------------------------------------------------------------------------------------------------------------------------------------------------290291_NS_INLINE NS::String* NS::Object::description() const292{293return sendMessage<String*>(this, _NS_PRIVATE_SEL(description));294}295296//-------------------------------------------------------------------------------------------------------------------------------------------------------------297298_NS_INLINE NS::String* NS::Object::debugDescription() const299{300return sendMessageSafe<String*>(this, _NS_PRIVATE_SEL(debugDescription));301}302303//-------------------------------------------------------------------------------------------------------------------------------------------------------------304305306