// $Id$

//#define WITH_ALLOC_CALLBACKS 0
#define GC_DEBUG             1

static __inline__ void *objc_malloc(size_t size);
static __inline__ void *objc_atomic_malloc(size_t size);
static __inline__ void *objc_valloc(size_t size);
static __inline__ void *objc_realloc(void *mem, size_t size);
static __inline__ void *objc_calloc(size_t nelem, size_t size);
static __inline__ void objc_free(void *mem);

#if !defined(OBJC_MEMORY)
#define OBJC_MEMORY

#ifndef OBJC_ERR_MEMORY
#  define OBJC_ERR_MEMORY 10             /* Out of memory */
#endif

objc_EXPORT void objc_error(id object, int code, const char* fmt, ...);

#if !WITH_ALLOC_CALLBACKS
#  if OBJC_WITH_GC
#    include "objc/gc.h"
#  else
#    include <stdlib.h>
#  endif
#endif

/*
** Standard functions for memory allocation and disposal.
** Users should use these functions in their ObjC programs so
** that they work properly with garbage collectors as well as
** can take advantage of the exception/error handling available.
*/
static __inline__ void *objc_malloc(size_t size) {
#if WITH_ALLOC_CALLBACKS
  void* res = (void*) (*_objc_malloc)(size);
#else
#if OBJC_WITH_GC
  void *res = GC_MALLOC(size);
#else
  void *res = malloc(size);
#endif
#endif
  
  if(!res)
    objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
  return res;
}

#include <stdio.h>

static __inline__ void *objc_atomic_malloc(size_t size) {
#if WITH_ALLOC_CALLBACKS
  void* res = (void*) (*_objc_atomic_malloc)(size);
#else
#if OBJC_WITH_GC
  void *res = GC_MALLOC_ATOMIC(size);
#else
  void *res = malloc(size);
#endif
#endif
  if(!res)
    objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
  return res;
}

static __inline__ void *objc_valloc(size_t size) {
#if WITH_ALLOC_CALLBACKS
  void* res = (void*) (*_objc_valloc)(size);
#else
#if OBJC_WITH_GC
  void *res = GC_MALLOC(size);
  if (res) memset(res, 0, size);
#else
  void *res = malloc(size);
#endif
#endif
  if(!res)
    objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
  return res;
}

static __inline__ void *objc_realloc(void *mem, size_t size) {
#if WITH_ALLOC_CALLBACKS
  void* res = (void*) (*_objc_realloc)(mem, size);
#else
#if OBJC_WITH_GC
  void *res = GC_REALLOC(mem, size);
#else
  void *res = realloc(mem, size);
#endif
#endif
  if(!res)
    objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
  return res;
}

static __inline__ void *objc_calloc(size_t nelem, size_t size) {
#if WITH_ALLOC_CALLBACKS
  void* res = (void*) (*_objc_calloc)(nelem, size);
#else
#if OBJC_WITH_GC
  register size_t s = nelem * size;
  void *res = GC_MALLOC(s);
  if (res) memset(res, 0, s);
#else
  void *res = calloc(nelem, size);
#endif
#endif
  if(!res)
    objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
  return res;
}

static __inline__ void objc_free(void *mem) {
#if WITH_ALLOC_CALLBACKS
  (*_objc_free)(mem);
#else
#if OBJC_WITH_GC
  GC_FREE(mem); mem = NULL;
#else
  free(mem);
#endif
#endif
}

#endif
