//==================================================
//Copyright $2010.
//Siemens Product Lifecycle Management Software Inc.
//All Rights Reserved.
//==================================================
//Copyright 2020 Siemens Digital Industries Software

/**
    @file

    This file contains the declarations for the non-member functions in the Teamcenter::NewOperator namespace in module libbase_utils, which can be used for overloading new operators
    \see http://en.wikipedia.org/wiki/Placement_syntax
    When overloading new operators you should overload *all* new operators, in particular the placement new operators used by std containers.
       C++ function name lookups start in the current scope (e.g. your class) and look for the desired name (e.g. operator new).
       If no instances of the name are found, it moves outward to the next enclosing scope and repeats.
       Once it finds a scope containing *at least one* instance of the name, it stops looking and works only with the matches
       it has found, which means that further outer scopes (e.g. the global scope) are not considered and any functions
       (like the placement new operators) in them are hidden.
       Instead, the compiler looks at all the instances of the name it has found, selects a function using overload resolution,
       and finally checks access rules to determine whether the selected function can be called.
       The outer scopes are ignored even if
         1. none of the overloads found has a compatible signature, meaning that none of them could possibly be the right one
         2. the signature-compatible function that's selected isn't accessible.
       That's why name hiding works the way it does in C++.

    Most Teamcenter classes are already using these SM memory new() operators by virtue of subclassing from Teamcenter::Object or inClass objects
    If you are sure your class isn't already using these SM memory new() operators
    you can add them to your class by using the macros
       1. TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_DECLARATIONS               -> .hxx
       2. TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_IMPLEMENTATIONS(CLASSNAME) -> .cxx
*/

#ifndef TEAMCENTER_BASE_NEWOPERATOR_HXX
#define TEAMCENTER_BASE_NEWOPERATOR_HXX


#include <cstddef> // defines std::size_t and the Null pointer macro "NULL"

#include <unidefs.h>
#include <mach_datatypes.h>

#include <base_utils/libbase_utils_exports.h>

// Macro to declare new() and delete() operators. Put this macro into the public: section of the .hxx file of your class if you are sure the operators aren't already inherited
#define TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_DECLARATIONS        \
    static void * operator new( std::size_t size );                \
    static void * operator new[]( std::size_t size );              \
    static void   operator delete( void * p, std::size_t size );   \
    static void   operator delete[]( void * p, std::size_t size ); \
    static void   operator delete( void * p );                     \
    static void   operator delete[]( void * p );                   \
                                                                   \
    static void * operator new( std::size_t, void * p );           \
    static void * operator new[]( std::size_t, void * p );         \
    static void   operator delete( void *, void * );               \
    static void   operator delete[]( void *, void * );

// Macro to implement new() and delete() operators. Put this macro into the .cxx file of your class if you are using TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_DECLARATIONS
#define TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_IMPLEMENTATIONS(CLASSNAME)                                                     \
    void * CLASSNAME::operator new( std::size_t size )                { return Teamcenter::NewOperator::alloc( size ); }      \
    void * CLASSNAME::operator new[]( std::size_t size )              { return Teamcenter::NewOperator::arrayalloc( size ); } \
    void   CLASSNAME::operator delete( void * p, std::size_t size )   { Teamcenter::NewOperator::dealloc( p, size ); }        \
    void   CLASSNAME::operator delete[]( void * p, std::size_t size ) { Teamcenter::NewOperator::arraydealloc( p, size ); }   \
    void   CLASSNAME::operator delete( void * p )                     { Teamcenter::NewOperator::dealloc( p, 0 ); }           \
    void   CLASSNAME::operator delete[]( void * p )                   { Teamcenter::NewOperator::arraydealloc( p, 0 ); }      \
                                                                                                                              \
    void * CLASSNAME::operator new( std::size_t, void * p )           { return p; }                                           \
    void * CLASSNAME::operator new[]( std::size_t, void * p )         { return p; }                                           \
    void   CLASSNAME::operator delete( void *, void * )               {}                                                      \
    void   CLASSNAME::operator delete[]( void *, void * )             {}

// Macro to declare and inline new() and delete() operators.
// Try to avoid this. Inlining functions that could be called from another library can cause serious problems.
// In most cases it is redundant because compilers can optimize function calls better without your help.
// Use TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_DECLARATIONS / TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATOR_IMPLEMENTATIONS(CLASSNAME) instead
#define TC_SM_MEMORY_CLASS_NEW_DELETE_OPERATORS_INLINED                                                                   \
    static void * operator new( std::size_t size )                { return Teamcenter::NewOperator::alloc( size ); }      \
    static void * operator new[]( std::size_t size )              { return Teamcenter::NewOperator::arrayalloc( size ); } \
    static void   operator delete( void * p, std::size_t size )   { Teamcenter::NewOperator::dealloc( p, size ); }        \
    static void   operator delete[]( void * p, std::size_t size ) { Teamcenter::NewOperator::arraydealloc( p, size ); }   \
    static void   operator delete( void * p )                     { Teamcenter::NewOperator::dealloc( p, 0 ); }           \
    static void   operator delete[]( void * p )                   { Teamcenter::NewOperator::arraydealloc( p, 0 ); }      \
                                                                                                                          \
    static void * operator new( std::size_t, void * p )           { return p; }                                           \
    static void * operator new[]( std::size_t, void * p )         { return p; }                                           \
    static void   operator delete( void *, void * )               {}                                                      \
    static void   operator delete[]( void *, void * )             {}



namespace Teamcenter
{
namespace NewOperator
{

BASE_UTILS_API void * alloc( std::size_t size );
BASE_UTILS_API void   dealloc( void * p, std::size_t size );
BASE_UTILS_API void * arrayalloc( std::size_t size );
BASE_UTILS_API void   arraydealloc( void * p, std::size_t size );

BASE_UTILS_API void setResourceTracking( bool onOrOff);
BASE_UTILS_API void * askRsrctrkPool();  // really a RSRCTRK_pool_t, but I don't want to include (and ship) rsrctrk.h

BASE_UTILS_API void init();
BASE_UTILS_API void setCurrentArea( const bool isUnloadable );
BASE_UTILS_API MACH_uint64_t askUnloadablePoolSize();
BASE_UTILS_API bool isCurrentAreaUnloadable();

} // namespace NewOperator
} // namespace Teamcenter

#include <base_utils/libbase_utils_undef.h>

#endif // TEAMCENTER_BASE_UTILS_SCOPEDSTATE_HXX
