/*
 * File: os2alloc.h
 *
 * This file was created to make STL able to be used in threads
 * created with DosCreateThread() by using OS/2 memory API's.
 *
 * by: Vincent Patrick LaBella
 * labelv@rpi.edu  http://www.rpi.edu/~labelv
 *
 */

#ifndef OS2ALLOC_H
#define OS2ALLOC_H

#include <new.h>
#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <iostream.h>
#include <algobase.h>

#ifndef OS2_ALLOC_MEM_FLAGS
// you may redefine these as you wish
// PAG_READ|PAG_WRITE|PAG_COMMIT
// use actual numbers so you can include os2.h before
// or after os2alloc.h
#define OS2_ALLOC_MEM_FLAGS 0x0001|0x0002|0x0010
#endif

// why aren't these defined in os2.h??
#define OS2_PAGE_SIZE 4096        // 4KB page size
#define OS2_MAX_SIZE  0xffffffffU // 4GB address space

template <class T>
inline T* allocate(long size, T*) {
    set_new_handler(0);
  T* tmp;
  DosAllocMem((void**)&tmp, size * sizeof(T), OS2_ALLOC_MEM_FLAGS);
    if (tmp == 0) {
  cerr << "out of memory" << endl;
  exit(1);
    }
    return tmp;
}

template <class T>
inline void deallocate(T* buffer) {
  DosFreeMem((void*) buffer);
}

template <class T1, class T2>
inline void construct( T1  *p, const T2& value )
{
    new(p)T1(value);
}

template <class T>
inline void destroy( T * pointer ) {
    pointer->~T();
}

inline void destroy(char  *) {}
inline void destroy(unsigned char  *) {}
inline void destroy(short  *) {}
inline void destroy(unsigned short *) {}
inline void destroy(int  *) {}
inline void destroy(unsigned int *) {}
inline void destroy(long  *) {}
inline void destroy(unsigned long *) {}
inline void destroy(float *) {}
inline void destroy(double *) {}

inline void destroy(char  *, char  *) {}
inline void destroy(unsigned char   *, unsigned char  *) {}
inline void destroy(short  *, short   *) {}
inline void destroy(unsigned short  *, unsigned short  *) {}
inline void destroy(int   *, int  *) {}
inline void destroy(unsigned int  *, unsigned int *) {}
inline void destroy(long  *, long *) {}
inline void destroy(unsigned long *, unsigned long  *) {}
inline void destroy(float  *, float  *) {}
inline void destroy(double  *, double  *) {}

template <class T>
class os2_allocator {
public:
    typedef T value_type;
    typedef T   * pointer;
    typedef const T   * const_pointer;
    typedef T  & reference;
    typedef const T   & const_reference;
    typedef unsigned long size_type;
    typedef long difference_type;
#ifdef __GNUG__
    static pointer allocate(size_type n) {
  return ::allocate((difference_type)n, (pointer)0);
    }
    static void deallocate(pointer p) { ::deallocate(p); }
    static pointer address(reference x) { return (pointer)&x; }
    static const_pointer const_address(const_reference x) {
  return (const_pointer)&x;
    }
    static size_type init_page_size() {
  return max(size_type(1), size_type(OS2_PAGE_SIZE/sizeof(T)));
    }
    static size_type max_size() {
  return max(size_type(1), size_type(OS2_MAX_SIZE/sizeof(T)));
    }
#else
    pointer allocate(size_type n) {
  return ::allocate((difference_type)n, (pointer)0);
    }
    void deallocate(pointer p) { ::deallocate(p); }
    pointer address(reference x) { return (pointer)&x; }
    const_pointer const_address(const_reference x) {
  return (const_pointer)&x;
    }
    size_type init_page_size() {
  return max(size_type(1), size_type(OS2_PAGE_SIZE/sizeof(T)));
    }
    size_type max_size() const {
  return max(size_type(1), size_type(OS2_MAX_SIZE/sizeof(T)));
    }
#endif
};

class os2_allocator<void> {
public:
    typedef void * pointer;
};

#endif
