SPB Git

spb/forge Public MIT

Forge — LLM training from scratch in pure C++20 + Metal on Apple Silicon.

C++ 61.2% C 23% Python 7.6% TeX 7.2% CMake 1.1%
10.9 KB · 303 lines cpp
Raw Blame History
1//-------------------------------------------------------------------------------------------------------------------------------------------------------------2//3// Foundation/NSObject.hpp4//5// Copyright 2020-2024 Apple Inc.6//7// Licensed under the Apache License, Version 2.0 (the "License");8// you may not use this file except in compliance with the License.9// You may obtain a copy of the License at10//11//     http://www.apache.org/licenses/LICENSE-2.012//13// Unless required by applicable law or agreed to in writing, software14// distributed under the License is distributed on an "AS IS" BASIS,15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.16// See the License for the specific language governing permissions and17// limitations under the License.18//19//-------------------------------------------------------------------------------------------------------------------------------------------------------------2021#pragma once2223//-------------------------------------------------------------------------------------------------------------------------------------------------------------2425#include "NSDefines.hpp"26#include "NSPrivate.hpp"27#include "NSTypes.hpp"2829#include <objc/message.h>30#include <objc/runtime.h>3132#include <type_traits>3334//-------------------------------------------------------------------------------------------------------------------------------------------------------------3536namespace NS37{38template <class _Class, class _Base = class Object>39class _NS_EXPORT Referencing : public _Base40{41public:42    _Class*  retain();43    void     release();4445    _Class*  autorelease();4647    UInteger retainCount() const;48};4950template <class _Class, class _Base = class Object>51class Copying : public Referencing<_Class, _Base>52{53public:54    _Class* copy() const;55};5657template <class _Class, class _Base = class Object>58class SecureCoding : public Referencing<_Class, _Base>59{60};6162class Object : public Referencing<Object, objc_object>63{64public:65    UInteger      hash() const;66    bool          isEqual(const Object* pObject) const;6768    class String* description() const;69    class String* debugDescription() const;7071protected:72    friend class Referencing<Object, objc_object>;7374    template <class _Class>75    static _Class* alloc(const char* pClassName);76    template <class _Class>77    static _Class* alloc(const void* pClass);78    template <class _Class>79    _Class* init();8081    template <class _Dst>82    static _Dst                   bridgingCast(const void* pObj);83    static class MethodSignature* methodSignatureForSelector(const void* pObj, SEL selector);84    static bool                   respondsToSelector(const void* pObj, SEL selector);85    template <typename _Type>86    static constexpr bool doesRequireMsgSendStret();87    template <typename _Ret, typename... _Args>88    static _Ret sendMessage(const void* pObj, SEL selector, _Args... args);89    template <typename _Ret, typename... _Args>90    static _Ret sendMessageSafe(const void* pObj, SEL selector, _Args... args);9192private:93    Object() = delete;94    Object(const Object&) = delete;95    ~Object() = delete;9697    Object& operator=(const Object&) = delete;98};99}100101//-------------------------------------------------------------------------------------------------------------------------------------------------------------102103template <class _Class, class _Base /* = Object */>104_NS_INLINE _Class* NS::Referencing<_Class, _Base>::retain()105{106    return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(retain));107}108109//-------------------------------------------------------------------------------------------------------------------------------------------------------------110111template <class _Class, class _Base /* = Object */>112_NS_INLINE void NS::Referencing<_Class, _Base>::release()113{114    Object::sendMessage<void>(this, _NS_PRIVATE_SEL(release));115}116117//-------------------------------------------------------------------------------------------------------------------------------------------------------------118119template <class _Class, class _Base /* = Object */>120_NS_INLINE _Class* NS::Referencing<_Class, _Base>::autorelease()121{122    return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(autorelease));123}124125//-------------------------------------------------------------------------------------------------------------------------------------------------------------126127template <class _Class, class _Base /* = Object */>128_NS_INLINE NS::UInteger NS::Referencing<_Class, _Base>::retainCount() const129{130    return Object::sendMessage<UInteger>(this, _NS_PRIVATE_SEL(retainCount));131}132133//-------------------------------------------------------------------------------------------------------------------------------------------------------------134135template <class _Class, class _Base /* = Object */>136_NS_INLINE _Class* NS::Copying<_Class, _Base>::copy() const137{138    return Object::sendMessage<_Class*>(this, _NS_PRIVATE_SEL(copy));139}140141//-------------------------------------------------------------------------------------------------------------------------------------------------------------142143template <class _Dst>144_NS_INLINE _Dst NS::Object::bridgingCast(const void* pObj)145{146#ifdef __OBJC__147    return (__bridge _Dst)pObj;148#else149    return (_Dst)pObj;150#endif // __OBJC__151}152153//-------------------------------------------------------------------------------------------------------------------------------------------------------------154155template <typename _Type>156_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret()157{158#if (defined(__i386__) || defined(__x86_64__))159    constexpr size_t kStructLimit = (sizeof(std::uintptr_t) << 1);160161    return sizeof(_Type) > kStructLimit;162#elif defined(__arm64__)163    return false;164#elif defined(__arm__)165    constexpr size_t kStructLimit = sizeof(std::uintptr_t);166167    return std::is_class_v<_Type> && (sizeof(_Type) > kStructLimit);168#else169#error "Unsupported architecture!"170#endif171}172173//-------------------------------------------------------------------------------------------------------------------------------------------------------------174175template <>176_NS_INLINE constexpr bool NS::Object::doesRequireMsgSendStret<void>()177{178    return false;179}180181//-------------------------------------------------------------------------------------------------------------------------------------------------------------182183template <typename _Ret, typename... _Args>184_NS_INLINE _Ret NS::Object::sendMessage(const void* pObj, SEL selector, _Args... args)185{186#if (defined(__i386__) || defined(__x86_64__))187    if constexpr (std::is_floating_point<_Ret>())188    {189        using SendMessageProcFpret = _Ret (*)(const void*, SEL, _Args...);190191        const SendMessageProcFpret pProc = reinterpret_cast<SendMessageProcFpret>(&objc_msgSend_fpret);192193        return (*pProc)(pObj, selector, args...);194    }195    else196#endif // ( defined( __i386__ )  || defined( __x86_64__ )  )197#if !defined(__arm64__)198        if constexpr (doesRequireMsgSendStret<_Ret>())199    {200        using SendMessageProcStret = void (*)(_Ret*, const void*, SEL, _Args...);201202        const SendMessageProcStret pProc = reinterpret_cast<SendMessageProcStret>(&objc_msgSend_stret);203        _Ret                       ret;204205        (*pProc)(&ret, pObj, selector, args...);206207        return ret;208    }209    else210#endif // !defined( __arm64__ )211    {212        using SendMessageProc = _Ret (*)(const void*, SEL, _Args...);213214        const SendMessageProc pProc = reinterpret_cast<SendMessageProc>(&objc_msgSend);215216        return (*pProc)(pObj, selector, args...);217    }218}219220//-------------------------------------------------------------------------------------------------------------------------------------------------------------221222_NS_INLINE NS::MethodSignature* NS::Object::methodSignatureForSelector(const void* pObj, SEL selector)223{224    return sendMessage<MethodSignature*>(pObj, _NS_PRIVATE_SEL(methodSignatureForSelector_), selector);225}226227//-------------------------------------------------------------------------------------------------------------------------------------------------------------228229_NS_INLINE bool NS::Object::respondsToSelector(const void* pObj, SEL selector)230{231    return sendMessage<bool>(pObj, _NS_PRIVATE_SEL(respondsToSelector_), selector);232}233234//-------------------------------------------------------------------------------------------------------------------------------------------------------------235236template <typename _Ret, typename... _Args>237_NS_INLINE _Ret NS::Object::sendMessageSafe(const void* pObj, SEL selector, _Args... args)238{239    if ((respondsToSelector(pObj, selector)) || (nullptr != methodSignatureForSelector(pObj, selector)))240    {241        return sendMessage<_Ret>(pObj, selector, args...);242    }243244    if constexpr (!std::is_void<_Ret>::value)245    {246        return _Ret(0);247    }248}249250//-------------------------------------------------------------------------------------------------------------------------------------------------------------251252template <class _Class>253_NS_INLINE _Class* NS::Object::alloc(const char* pClassName)254{255    return sendMessage<_Class*>(objc_lookUpClass(pClassName), _NS_PRIVATE_SEL(alloc));256}257258//-------------------------------------------------------------------------------------------------------------------------------------------------------------259260template <class _Class>261_NS_INLINE _Class* NS::Object::alloc(const void* pClass)262{263    return sendMessage<_Class*>(pClass, _NS_PRIVATE_SEL(alloc));264}265266//-------------------------------------------------------------------------------------------------------------------------------------------------------------267268template <class _Class>269_NS_INLINE _Class* NS::Object::init()270{271    return sendMessage<_Class*>(this, _NS_PRIVATE_SEL(init));272}273274//-------------------------------------------------------------------------------------------------------------------------------------------------------------275276_NS_INLINE NS::UInteger NS::Object::hash() const277{278    return sendMessage<UInteger>(this, _NS_PRIVATE_SEL(hash));279}280281//-------------------------------------------------------------------------------------------------------------------------------------------------------------282283_NS_INLINE bool NS::Object::isEqual(const Object* pObject) const284{285    return sendMessage<bool>(this, _NS_PRIVATE_SEL(isEqual_), pObject);286}287288//-------------------------------------------------------------------------------------------------------------------------------------------------------------289290_NS_INLINE NS::String* NS::Object::description() const291{292    return sendMessage<String*>(this, _NS_PRIVATE_SEL(description));293}294295//-------------------------------------------------------------------------------------------------------------------------------------------------------------296297_NS_INLINE NS::String* NS::Object::debugDescription() const298{299    return sendMessageSafe<String*>(this, _NS_PRIVATE_SEL(debugDescription));300}301302//-------------------------------------------------------------------------------------------------------------------------------------------------------------303