// MemoryAllocation.h
//
// Copyright 1999 Diehl Graphsoft, Inc.
// All Rights Reserved.
//
// This is the core MiniCad memory allocation engine. It works in concert with
// MemoryMaintenance.cpp/.h to allocate Mac and C++ memory, manage the grow zone,
// fail gracefully when possible and forcefully when necessary. This file accumulates
// code which used to be in PUtils, AltMemory, and BugMemory.
//
// Started 11/07/96 by Paul Pharr
//
// SourceSafe information for this version:
//    $Revision: 3 $
//    $Date: 1/30/01 8:00a $
//    $Author: Paul $


#if !defined(_MEMORYALLOCATION_)
#define _MEMORYALLOCATION_

#pragma once

#if GS_SHELL_BUILD && _WINDOWS

	// When building the MFC application, I think it's better to use the 'new' provided
	// by MFC (which does not throw). I'm afraid it will cause hidden nasties if we use
	// our own 'new' instead of MFC's global 'new' or (this is the important one:) their
	// 'CObject::new' method.  [DMB 5/28/99 & 8/2/00]

	#define NEW_NOTHROW new

#else

#include <stdlib.h>
#include <new>


#if !GS_SHELL_BUILD && !GS_CORE_BUILD && !GS_COMP_BUILD && !GS_PROTECTION_BUILD && GS_WIN
	// Include Memory.h now, so all our special defines don't screw it up later.
	#include <MacMemory.h>
#elif GS_WIN
	#ifndef nil
		#define nil 0
	#endif
	typedef char   *Ptr;
	typedef Ptr	   *Handle;
	typedef long	Size;
	typedef short	OSErr;
#endif

#include "GSUtil.h"


////////////////////
// OVERVIEW
////////////////////

/*

There are two general types of memory allocation within MiniCad: Those allocations
which can return failure, and those which cannot.
	
	Allocations which cannot return failure rely on the Mac's (and Altura's)
		growZone functionality, which provides a mechanism by which a memory
		failure handler (similar to new_handler in c++) is called when there is
		not enough memory. This handler is responsible for finding enough memory
		or terminating the application. Usually, it can satisfy the request by
		releasing part of an emergency block it keeps around just for that purpose.
		Since memory failure can terminate the application, though, it does not
		provide a good general solution.

		Allocation families which do not return errors:
			
			NewHandleGZ and other GZ routines.
			
			NEW_GZ

	Allocations which do return errors rely on their client code to ALWAYS do the
		appropriate thing if an allocation fails. If the client code does not notice
		a nil returned from an allocation routine, the application will crash when
		this memory is used. Even worse, if the application is in the middle of a complex
		operation, failure to get memory can set off a chain reaction of incorrect error
		handling which can result in a corrupted file.

		Allocation families which return errors:
			
			NewHandleCk and other Ck routines.
			
			NEW_THROW
			
			NEW_NOTHROW
	
	
	Allocation routines from the standard C library such as malloc() and its many cousins
		have not been set up to handle errors gracefully and SHOULD NEVER BE USED. Use of
		these functions will compromize the stability of the application.

*/



/////////////////////////////////////////////////////////////////////////////////////////
// Define macro used to export functions.

#if GS_CORE_DLL
	#if _WINDOWS
		#if GS_CORE_BUILD
			#define GS_MEMORY_EXPORT	__declspec( dllexport )
		#else
			#define GS_MEMORY_EXPORT	__declspec( dllimport )
		#endif
	#else
		#define GS_MEMORY_EXPORT
	#endif
#else
	#define GS_MEMORY_EXPORT
#endif



/////////////////////////////////
// Define Query Functions
/////////////////////////////////

GS_MEMORY_EXPORT size_t GSFreeMem();
GS_MEMORY_EXPORT size_t GSMaxBlock();


/////////////////////////////////
// Define GZ_ versions of allocation calls 
/////////////////////////////////

// If you want to use native Mac memory allocation calls protected by the grow zone
// function and you want NO parameter validation or error checking done on those calls,
// use the GZ_ calls. If the call you want is not in this section, then there is no debug
// verion of the call, and therefore no need for a non-debug version.
//
// These calls replace the NO_DEBUG_MEM_ALIAS flag and its functionality. Debug and
// non-debug calls can now be made on a call by call basis rather than turning off
// debugging on a file by file basis


// functions that have a GZ equivalent:

GS_MEMORY_EXPORT Handle	NewHandleGZ_(Size byteCount);
GS_MEMORY_EXPORT Handle	NewHandleClearGZ_(Size byteCount);
GS_MEMORY_EXPORT Ptr	NewPtrGZ_(Size byteCount);
GS_MEMORY_EXPORT Ptr	NewPtrClearGZ_(Size byteCount);

GS_MEMORY_EXPORT void	SetHandleSizeGZ_(Handle h, Size byteCount);
GS_MEMORY_EXPORT OSErr	HandToHandGZ_(Handle *h);

GS_MEMORY_EXPORT OSErr	PtrToHandGZ_(const void *p, Handle *h, Size byteCount);
GS_MEMORY_EXPORT OSErr	PtrToXHandGZ_(const void *p, Handle h, Size byteCount);
GS_MEMORY_EXPORT OSErr	PtrAndHandGZ_(const void *p, Handle h, Size byteCount);
GS_MEMORY_EXPORT OSErr	HandAndHandGZ_(Handle h1, Handle h2);


// functions which have debug code, but no GZ equivalent:

GS_MEMORY_EXPORT Handle	NewHandleSys_(Size byteCount);
GS_MEMORY_EXPORT Handle	NewHandleSysClear_(Size byteCount);
GS_MEMORY_EXPORT Ptr	NewPtrSys_(Size byteCount);
GS_MEMORY_EXPORT Ptr	NewPtrSysClear_(Size byteCount);

GS_MEMORY_EXPORT void	SetPtrSize_(Ptr p, Size byteCount);

GS_MEMORY_EXPORT void	DisposePtr_(Ptr p);
GS_MEMORY_EXPORT void	DisposeHandle_(Handle h);

GS_MEMORY_EXPORT Handle	NewEmptyHandle_();
GS_MEMORY_EXPORT void	ReallocateHandle_(Handle h, Size byteCount);
GS_MEMORY_EXPORT void	EmptyHandle_(Handle h);



////////////////////
// D_ Memory calls
////////////////////

// These are debug versions of the Mac memory calls which do additional checking of
// parameters when compiled into a development build. They are used by all of our higher
// level calls to perform the most thorough checks possible. They are declared in AltMemory.h
// and defined in AltMemory.cp.

// If you don't want the debug code to be used in very low level memory calls, use the non-debug
// calls defined above.

#if BUG

	// Function prototypes.
	GS_MEMORY_EXPORT Handle	D_NewHandle(Size byteCount);
	GS_MEMORY_EXPORT Handle	D_NewHandleSys(Size byteCount);
	GS_MEMORY_EXPORT Handle	D_NewHandleClear(Size byteCount);
	GS_MEMORY_EXPORT Handle	D_NewHandleSysClear(Size byteCount);
	GS_MEMORY_EXPORT Handle	D_NewEmptyHandle();
	GS_MEMORY_EXPORT void	D_SetHandleSize(Handle h, Size newSize);
	GS_MEMORY_EXPORT void	D_ReallocHandle(Handle h, Size byteCount);
	GS_MEMORY_EXPORT void	D_EmptyHandle(Handle h);
	GS_MEMORY_EXPORT void	D_DisposeHandle(Handle h);
	GS_MEMORY_EXPORT Ptr	D_NewPtr(Size byteCount);
	GS_MEMORY_EXPORT Ptr	D_NewPtrSys(Size byteCount);
	GS_MEMORY_EXPORT Ptr	D_NewPtrClear(Size byteCount);
	GS_MEMORY_EXPORT Ptr	D_NewPtrSysClear(Size byteCount);
	GS_MEMORY_EXPORT void	D_SetPtrSize(Ptr p, Size newSize);
	GS_MEMORY_EXPORT void	D_DisposePtr(Ptr p);
	GS_MEMORY_EXPORT OSErr	D_HandToHand(Handle *h);
	GS_MEMORY_EXPORT OSErr	D_PtrToXHand(const void *p, Handle h, Size byteCount);
	GS_MEMORY_EXPORT OSErr	D_PtrToHand(const void *p, Handle *h, Size byteCount);
	GS_MEMORY_EXPORT OSErr	D_HandAndHand(Handle h1, Handle h2);
	GS_MEMORY_EXPORT OSErr	D_PtrAndHand(const void *p, Handle h, Size byteCount);

	#if !GS_ALLOW_MAC_MEMORY_CALLS
		// The only time this section is skipped is when building "MemoryAllocation.cpp".

		// Get rid of current defines done by mac header files.
		#undef DisposHandle
		#undef DisposPtr
		#undef DisposeHandle
		#undef DisposePtr

		// Replace all Mac memory calls through debug functions.
		#define NewHandle			D_NewHandle
		#define NewHandleSys		D_NewHandleSys
		#define NewHandleClear		D_NewHandleClear
		#define NewHandleSysClear	D_NewHandleSysClear
		#define NewEmptyHandle		D_NewEmptyHandle
		#define SetHandleSize		D_SetHandleSize
		#define ReallocateHandle	D_ReallocHandle
		#define EmptyHandle			D_EmptyHandle
		#define DisposeHandle		D_DisposeHandle
		#define NewPtr				D_NewPtr
		#define NewPtrSys			D_NewPtrSys
		#define NewPtrClear			D_NewPtrClear
		#define NewPtrSysClear		D_NewPtrSysClear
		#define SetPtrSize			D_SetPtrSize
		#define DisposePtr			D_DisposePtr
		#define HandToHand			D_HandToHand
		#define PtrToXHand			D_PtrToXHand
		#define PtrToHand			D_PtrToHand
		#define HandAndHand			D_HandAndHand
		#define PtrAndHand			D_PtrAndHand

	#endif // !GS_ALLOW_MAC_MEMORY_CALLS

#endif // BUG



/////////////////////////////////
// Define GZ versions of allocation calls 
/////////////////////////////////

// The GZ versions of Mac allocation calls allow the naked OS calls to be
// used where necessary.

// The GZ routines will take memory from the GrowZone if necessary. They
// are guaranteed to never return failure, but in extreme low memory situations,
// they can cause the application to QUIT UNEXPECTEDLY. They should be used for
// only the most critical or low-level memory requirements.

// If you use the GZ routines, you are risking product stability in low
// memory situations. Any use of GZ routines should meet the following
// guidelines:

//		Allocations should be small.
//
//		There should be no case where GZ routines should be used to allocate a large
//		number of blocks in succession where the number or size of the blocks is
//		dependent on any kind of user input or number of objects in a file.

//		Any code which processes a lot of information should be built to handle failure
//		of any memory allocation call used anywhere in the algorithm, and should use Ck
//		style memory allocation exclusively.

// NOTE - these calls go through the D_ calls in the dev version.

GS_MEMORY_EXPORT Handle	NewHandleGZ(Size byteCount);
GS_MEMORY_EXPORT Handle	NewHandleClearGZ(Size byteCount);
GS_MEMORY_EXPORT Ptr	NewPtrGZ(Size byteCount);
GS_MEMORY_EXPORT Ptr	NewPtrClearGZ(Size byteCount);

GS_MEMORY_EXPORT void	SetHandleSizeGZ(Handle h, Size byteCount);
GS_MEMORY_EXPORT OSErr	HandToHandGZ(Handle *h);

GS_MEMORY_EXPORT OSErr	PtrToHandGZ(const void *p, Handle *h, Size byteCount);
GS_MEMORY_EXPORT OSErr	PtrToXHandGZ(const void *p, Handle h, Size byteCount);
GS_MEMORY_EXPORT OSErr	PtrAndHandGZ(const void *p, Handle h, Size byteCount);
GS_MEMORY_EXPORT OSErr	HandAndHandGZ(Handle h1, Handle h2);



/////////////////////////////////
// Convenience Routines 
/////////////////////////////////

#if GS_CORE_BUILD || defined(__MEMORY__)

Boolean	HandleIsLocked (Handle handle);
Boolean	HandleIsPurgeable (Handle handle);
Boolean	HandleIsResource (Handle handle);

#endif



/////////////////////////////////
// Redefine most OS memory calls to generate a compile error 
/////////////////////////////////

// You can never call these allocation calls directly.  You must use
// either NewHandleGZ or NewHandleCk in place of the native NewHandle.

#if !GS_ALLOW_MAC_MEMORY_CALLS
	// The only time this section is skipped is when building "MemoryAllocation.cpp".

	#undef NewHandle
	#define NewHandle			BogusNewHandle

	#undef NewHandleClear
	#define NewHandleClear		BogusNewHandleClear

	#undef NewPtr
	#define NewPtr				BogusNewPtr

	#undef NewPtrClear
	#define NewPtrClear			BogusNewPtrClear

	#undef SetHandleSize
	#define SetHandleSize		BogusSetHandleSize

	#undef HandToHand
	#define HandToHand			BogusHandToHand

	#undef PtrToHand
	#define PtrToHand			BogusPtrToHand

	#undef PtrToXHand
	#define PtrToXHand			BogusPtrToXHand

	#undef HandAndHand
	#define HandAndHand			BogusHandAndHand

	#undef PtrAndHand
	#define PtrAndHand			BogusPtrAndHand

#endif // !GS_ALLOW_MAC_MEMORY_CALLS



//////////////////////////////////////////
// Define Ck versions of allocation calls 
//////////////////////////////////////////

// The Ck routines will never dip into the GrowZone.
// They are very careful not to do too much work to satisfy a hopelessly large memory
//		request, thereby avoiding a great deal of thrashing.
// They return nil or false if they fail.
// These functions should be used for almost all memory allocation.

void	GS_MEMORY_EXPORT SignalLowMemory();
			// SignalLowMemory is used by all Ck style allocation routines to notify
			// the application (and the user) that a memory allocation failure has
			// occurred.

GS_MEMORY_EXPORT Ptr		NewPtrCk(Size byteCount);
GS_MEMORY_EXPORT Ptr		NewPtrClearCk(Size byteCount);
GS_MEMORY_EXPORT void		DisposePtrCk(Ptr p);
GS_MEMORY_EXPORT Handle		NewHandleCk(Size byteCount);
GS_MEMORY_EXPORT Handle		NewHandleClearCk(Size byteCount);
GS_MEMORY_EXPORT Size		GetHandleSizeCk(Handle h);
GS_MEMORY_EXPORT Boolean	SetHandleSizeCk(Handle h, Size newSize);
GS_MEMORY_EXPORT void		HLockCk(Handle h);
GS_MEMORY_EXPORT void		HUnlockCk(Handle h);
GS_MEMORY_EXPORT char		HGetStateCk(Handle h);
GS_MEMORY_EXPORT void		HSetStateCk(Handle h, char flags);
GS_MEMORY_EXPORT void		ReduceHandleSizeCk(Handle h, Size newSize);
GS_MEMORY_EXPORT void		HandToHandCk(Handle &h);
GS_MEMORY_EXPORT void		PtrToHandCk(const void *srcPtr, Handle &dstHndl, long size);
GS_MEMORY_EXPORT Boolean	PtrToXHandCk(const void *srcPtr, Handle dstHndl, long size);
GS_MEMORY_EXPORT Boolean	HandAndHandCk(Handle hand1, Handle hand2);
GS_MEMORY_EXPORT Boolean	PtrAndHandCk(const void *ptr1, Handle hand2, long size);

inline Handle CopyHandCk(Handle h) { Handle hCopy = h; HandToHandCk(hCopy); return hCopy; }



/////////////////////////////////
// DisposeHandleSetNil
/////////////////////////////////

GS_MEMORY_EXPORT void LLDisposeHandleSetNil(Handle& h);

template <class T>
	inline void DisposeHandleSetNil(T** &h)
		{ LLDisposeHandleSetNil(CAST(Handle, h)); }





/////////////////////////////////
// Memory Management globals 
/////////////////////////////////

GS_MEMORY_EXPORT extern Boolean opAbortLowMem;

	// opAbortLowMem is set to true if a memory allocation routine fails.
	// The next time the application reaches the main event loop, a low
	// memory dialog is presented to the user.

GS_MEMORY_EXPORT extern Boolean gNoGrowZone;

	// gNoGrowZone is used to communicate with the growZone management code. When
	// gNoGrowZone is true, then the growZone function will not release any part
	// of its memory pool if it is called. This is the mechanism which allows
	// memory allocations to fail. If gNoGrowZone is false, then the growZone
	// function will take any measures necessary to satisfy a memory request. If
	// the request cannot be satisfied, the user is given the opportunity to save
	// their file (which may or may not be successful depending on the internal state
	// of MiniCad's data structures) and the application is terminated.

GS_MEMORY_EXPORT extern Boolean gQuietGrowZone;

	// gQuietGrowZone can be set to true to temporarily cause the grow zone to
	// silently fulfill minor memory requests without complaining about low
	// memory conditions. This is typically used when you want the grow zone
	// to provide enough memory that you can inform the user about low memory.
	// This cannot be left in the true state through the main event loop.

/*



////////////////////////////////////////////////
// METROWERKS NEW
////////////////////////////////////////////////

Here's how the Metrowerks new works:

	On the first allocation, a 64k block is allocated in the application heap, from which
	sub-allocations are doled out as needed. If a request cannot be satisfied from this pool,
	an addtional 64k block is allocated using NewPtr. If the NewPtr call fails, then a NewPtr call
	for a block of the exact size needed is attempted. If this fails, then NULL is returned.
	
	If the block being allocated is 2k or larger, it is allocated directly by NewPtr.
	
	The blocks which make up the C++ memory pool are never returned to the operating system.
	2k and larger blocks are de-allocated upon delete.
	
	Since we can't get a reliable count of the free space in the sub-allocation blocks
	from the runtime library, we can't intelligently prevent unnecessary and futile attempts
	to satisfy a large memory request without changing the library code.


////////////////////////////////////////////////
// MICROSOFT NEW
////////////////////////////////////////////////

Here's how the Microsoft new works:

	MSVC's global operator new returns NULL upon failure. It also uses a sub-allocation
	mechanism, but I'm not sure of the details.

*/


////////////////////////////////////////////////
// operator new Redefinitions
////////////////////////////////////////////////

#if BUG
	#if _WINDOWS
		#define	_CRTDBG_MAP_ALLOC 1
		#include <crtdbg.h>
	#else
		#define DEBUG_NEW	DEBUG_NEW_OFF
		#include <DebugNew.h>
		// DebugNew.h defines a NEW_NOTHROW where you are expected to explicitly
		//  pass std::nothrow, but we do it as part of our macro, so remove theirs
		#undef NEW_NOTHROW
		// undefine the DEBUG_NEW flag (needed in DebugNew.h) so we can redefine it as a macro
		#undef DEBUG_NEW
	#endif
#endif




// HACK - for some strange reason, MSVC doesn't support = {} here!!
#if BUG
	#if _WINDOWS
		#define NNA_GDB_NOT_OPAQUE_STRUCTURE_MARKER
	#else
		#define NNA_GDB_NOT_OPAQUE_STRUCTURE_MARKER char notOpaqueStructureMarker
	#endif
#else
	#define NNA_GDB_NOT_OPAQUE_STRUCTURE_MARKER
#endif

struct usegrowzone_t { NNA_GDB_NOT_OPAQUE_STRUCTURE_MARKER; };
#if __MWERKS__
	const usegrowzone_t usegrowzone = {};
#else
	const usegrowzone_t usegrowzone = usegrowzone_t();
#endif

struct usethrow_t { NNA_GDB_NOT_OPAQUE_STRUCTURE_MARKER; };
#if __MWERKS__
	const usethrow_t usethrow = {};
#else
	const usethrow_t usethrow = usethrow_t();
#endif

struct nothroworgrowzone_t { NNA_GDB_NOT_OPAQUE_STRUCTURE_MARKER; };
#if __MWERKS__
	const nothroworgrowzone_t nothroworgrowzone = {};
#else
	const nothroworgrowzone_t nothroworgrowzone = nothroworgrowzone_t();
#endif



////////////////////////////////////////////////
// new_nothrow
////////////////////////////////////////////////

// This is the basic implementation of an allocator which does not throw
// We can't use nothrow syntax on Windows, so we catch any exceptions
// which might be thrown. Note that this allocator works correctly regardless
// of whether the new implementation might throw exceptions.

// Exceptions depend on the allocator being set up correctly in SetUpMemory() in
// MemoryMaintenance.cp

#if BUG
inline void *new_nothrow(size_t s, const char* file, int line) //throw(bad_alloc)
#else
inline void *new_nothrow(size_t s) //throw(bad_alloc);
#endif
{
	try {
		#if BUG
			#if _WINDOWS
				return ::operator new(s, _NORMAL_BLOCK, file, line);
			#else
				return ::operator new(s); // , file, line); // Turned off for the Mach-O version of VectorWorks.
			#endif
		#else
			return ::operator new(s);
		#endif
	}
	catch(std::bad_alloc) {
		return nil;
	}
}

#if !_WINDOWS
#if BUG
inline void *new_nothrow_array(size_t s, const char* file, int line) //throw(bad_alloc)
#else
inline void *new_nothrow_array(size_t s) //throw(bad_alloc);
#endif
{
	try {
		#if BUG && GS_MAC_CFM
			return ::operator new[](s, file, line);
		#else
			return ::operator new[](s);
		#endif
	}
	catch(std::bad_alloc) {
		return nil;
	}
}
#endif


////////////////////////////////////////////////
// new(nothrow)
////////////////////////////////////////////////

// since we want new(nothrow) to fail without using growZone memory, we are defining this
// for both Mac and Win. The Mac version will override its equivalent in the runtime library.

#if BUG
inline void *operator new(size_t s, const nothroworgrowzone_t&, const char* file, int line) //throw()
#else
inline void *operator new(size_t s, const nothroworgrowzone_t&) // throw()
#endif
{
	Boolean saveGNoGrow = gNoGrowZone;			// don't use the growZone
	gNoGrowZone = true;
	
	#if BUG
	void* result = new_nothrow(s, file, line);
	#else
	void* result = new_nothrow(s);
	#endif
	
	gNoGrowZone = saveGNoGrow;
	
	if (!result)
		SignalLowMemory(); // signal the low mem alert

	return result;
}


#if !_WINDOWS
// CW4 Pro compilers require a separate implementation for new[]

#if BUG
inline void *operator new[](size_t s, const nothroworgrowzone_t&, const char* file, int line) //throw()
#else
inline void *operator new[](size_t s, const nothroworgrowzone_t&) // throw()
#endif
{
	Boolean saveGNoGrow = gNoGrowZone;			// don't use the growZone
	gNoGrowZone = true;
	
	#if BUG
	void* result = new_nothrow_array(s, file, line);
	#else
	void* result = new_nothrow_array(s);
	#endif
	
	gNoGrowZone = saveGNoGrow;
	
	if (!result)
		SignalLowMemory(); // signal the low mem alert

	return result;
}

#endif // !_WINDOWS


////////////////////////////////////////////////
// new(usethrow)
////////////////////////////////////////////////

// throws on allocation failure, but doesn't use growZone memory

#if BUG
inline void *operator new(size_t s, const usethrow_t&, const char* file, int line) // throw(bad_alloc)
#else
inline void *operator new(size_t s, const usethrow_t&) // throw(bad_alloc)
#endif
{
	#if BUG
	void* result = ::operator new(s, nothroworgrowzone, file, line);	// call our new which doesn't throw, and doesn't use growZone memory
	#else
	void* result = ::operator new(s, nothroworgrowzone);				// call our new which doesn't throw, and doesn't use growZone memory
	#endif

	if (!result) {
		SignalLowMemory();									// signal the low mem alert
		throw std::bad_alloc();								// throw if we fail
	}
	
	return result;
}

#if !_WINDOWS
// CW4 Pro compilers require a separate implementation for new[]

#if BUG
inline void *operator new[](size_t s,const usethrow_t&, const char* file, int line) // throw(bad_alloc)
#else
inline void *operator new[](size_t s,const usethrow_t&) // throw(bad_alloc)
#endif
{
	#if BUG
	void* result = ::operator new[](s, nothroworgrowzone, file, line);	
	#else
	void* result = ::operator new[](s, nothroworgrowzone);				
	#endif
	
	if (!result) {
		SignalLowMemory();									// signal the low mem alert
		throw std::bad_alloc();								// throw if we fail
	}

	return result;
}
#endif


////////////////////////////////////////////////
// new(usegrowzone)
////////////////////////////////////////////////

// new(usegrowzone) will use growzone memory to satisfy an allocation request. It should
// never fail under any circumstance on any platform. If an allocation request is made which
// cannot be satisfied, the application will terminate.

#if BUG
	inline void *operator new(size_t s, const usegrowzone_t&, const char* file, int line) // throw()
	{
		return new_nothrow(s, file, line);
	}
#else
	inline void *operator new(size_t s, const usegrowzone_t&) // throw()
	{
		return new_nothrow(s);
	}
#endif

#if !_WINDOWS
	// CW4 Pro compilers require a separate implementation for new[]

	#if BUG
		inline void *operator new[](size_t s, const usegrowzone_t&, const char* file, int line) // throw()
		{
			return new_nothrow_array(s, file, line);
		}
	#else
		inline void *operator new[](size_t s, const usegrowzone_t&) // throw()
		{
			return new_nothrow_array(s);
		}
	#endif

#endif // !_WINDOWS


////////////////////////////////////////////////
// MACRO Definitions
////////////////////////////////////////////////


// NEW_THROW  - Mainstream version of operator new which throws bad_alloc on failure.
//
// NEW_NOTHROW	- Mainstream version of operator new which returns NULL on failure.
//
// NEW_GZ  - Low level allocator which has no failure mechanism other than application termination.
//           DO NOT USE THIS unless you have a very good reason
//
// Usage examples:
//
//   object* objPtr = NEW_NOTHROW Object;	// returns nil on failure, does not throw, does not use growZone memory
//   object* objPtr = NEW_THROW Object;		// throws bad_alloc on failure, does not use growZone memory
//   object* objPtr = NEW_GZ Object;		// quits application on failure, uses growZone memory

#if BUG
	// these are the macros which are responsible for passing the proper
	// debug info for leak location identification
	#define NEW_NOTHROW		new(nothroworgrowzone, THIS_FILE, __LINE__)
	#define NEW_THROW		new(usethrow, THIS_FILE, __LINE__)
	#define NEW_GZ			new(usegrowzone, THIS_FILE, __LINE__)
#else
	#define NEW_NOTHROW		new(nothroworgrowzone)
	#define NEW_THROW		new(usethrow)
	#define NEW_GZ			new(usegrowzone)
#endif

// this will go away - PCP
#ifdef DEBUG_NEW
	#undef DEBUG_NEW
#endif
#define DEBUG_NEW		NEW_NOTHROW


#endif // GS_SHELL_BUILD && _WINDOWS

#endif // _MEMORYALLOCATION_
