text: // File: crn_mem.h
  // See Copyright Notice and license at the end of inc/crnlib.h
  #pragma once
  
  #ifndef CRNLIB_MIN_ALLOC_ALIGNMENT
  #define CRNLIB_MIN_ALLOC_ALIGNMENT sizeof(size_t) * 2
  #endif
  
  namespace crnlib {
  #if CRNLIB_64BIT_POINTERS
  const uint64 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x400000000ULL;
  #else
  const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U;
  #endif
  
  void* crnlib_malloc(size_t size);
  void* crnlib_malloc(size_t size, size_t* pActual_size);
  void* crnlib_realloc(void* p, size_t size, size_t* pActual_size = NULL, bool movable = true);
  void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size = NULL);
  void crnlib_free(void* p);
  size_t crnlib_msize(void* p);
  void crnlib_print_mem_stats();
  void crnlib_mem_error(const char* p_msg);
  
  // omfg - there must be a better way
  
  template <typename T>
  inline T* crnlib_new() {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    if (CRNLIB_IS_SCALAR_TYPE(T))
      return p;
    return helpers::construct(p);
  }
  
  template <typename T, typename A>
  inline T* crnlib_new(const A& init0) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0);
  }
  
  template <typename T, typename A>
  inline T* crnlib_new(A& init0) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0);
  }
  
  template <typename T, typename A, typename B>
  inline T* crnlib_new(const A& init0, const B& init1) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1);
  }
  
  template <typename T, typename A, typename B, typename C>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2);
  }
  
  template <typename T, typename A, typename B, typename C, typename D>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9, const K& init10) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9, init10);
  }
  
  template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L>
  inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9, const K& init10, const L& init11) {
    T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
    return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9, init10, init11);
  }
  
  template <typename T>
  inline T* crnlib_new_array(uint32 num) {
    if (!num)
      num = 1;
  
    uint64 total = CRNLIB_MIN_ALLOC_ALIGNMENT + sizeof(T) * num;
    if (total > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) {
      crnlib_mem_error("crnlib_new_array: Array too large!");
      return NULL;
    }
    uint8* q = static_cast<uint8*>(crnlib_malloc(static_cast<size_t>(total)));
  
    T* p = reinterpret_cast<T*>(q + CRNLIB_MIN_ALLOC_ALIGNMENT);
  
    reinterpret_cast<uint32*>(p)[-1] = num;
    reinterpret_cast<uint32*>(p)[-2] = ~num;
  
    if (!CRNLIB_IS_SCALAR_TYPE(T)) {
      helpers::construct_array(p, num);
    }
    return p;
  }
  
  template <typename T>
  inline void crnlib_delete(T* p) {
    if (p) {
      if (!CRNLIB_IS_SCALAR_TYPE(T)) {
        helpers::destruct(p);
      }
      crnlib_free(p);
    }
  }
  
  template <typename T>
  inline void crnlib_delete_array(T* p) {
    if (p) {
      const uint32 num = reinterpret_cast<uint32*>(p)[-1];
      const uint32 num_check = reinterpret_cast<uint32*>(p)[-2];
      CRNLIB_ASSERT(num && (num == ~num_check));
      if (num == ~num_check) {
        if (!CRNLIB_IS_SCALAR_TYPE(T)) {
          helpers::destruct_array(p, num);
        }
  
        crnlib_free(reinterpret_cast<uint8*>(p) - CRNLIB_MIN_ALLOC_ALIGNMENT);
      }
    }
  }
  
  }  // namespace crnlib
  #define CRNLIB_DEFINE_NEW_DELETE                                \
    void* operator new(size_t size) {                             \
      void* p = crnlib::crnlib_malloc(size);                      \
      if (!p)                                                     \
        crnlib_fail("new: Out of memory!", __FILE__, __LINE__);   \
      return p;                                                   \
    }                                                             \
    void* operator new[](size_t size) {                           \
      void* p = crnlib::crnlib_malloc(size);                      \
      if (!p)                                                     \
        crnlib_fail("new[]: Out of memory!", __FILE__, __LINE__); \
      return p;                                                   \
    }                                                             \
    void operator delete(void* p_block) {                         \
      crnlib::crnlib_free(p_block);                               \
    }                                                             \
    void operator delete[](void* p_block) {                       \
      crnlib::crnlib_free(p_block);                               \
    }
  