/* exarray.cpp

    Динамические массивы и указатели с
    автоматической проверкой индекса
    (сокращенный вариант).
    Функции распределения памяти.

    (C) Р.Н.Шакиров, ИМаш УрО PAH, 1998 - 2000
    All Rights Reserved.
*/
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <new.h>

//  Функция exmrealloc выделяет, удлиняет,
//  укорачивает и освобождает блоки памяти,
//  заполненные нулями.
//  При переполнении разрядной сетки индекса
//  вызывается функция abort().
//  При нехватке памяти вызывается функция,
//  установленная по set_new_handler из
//  new.h, а если ее нет - то abort().

void    exmrealloc (void **p, unsigned size,
                  unsigned oldsize)
{
  void *pp = *p;
  if (size)     // Выделение памяти.
  {
    if (size > (~0u)-9)  // Обход ошибки realloc().
      abort();
    while ((pp = realloc (*p, size)) == NULL)
    {           // Вызов new_handler().
      typedef void (*pvfunc) (void);
      pvfunc pvf = set_new_handler (NULL);
      set_new_handler (pvf);
      if (pvf) (*pvf)(); else abort();
    }
    if (size > oldsize)
      memset            // Обнуление.
       ((char*)pp + oldsize, 0, size - oldsize);
  }
  else          // Оcвобождение памяти.
  { 
    if (pp) { free (pp); pp = NULL; }
  }
  *p = pp;
}

//  Функция excalcsize вычисляет размер блока
//  памяти в байтах, который должен быть не
//  меньше требуемого, для чего начальный
//  размер SIZE_MOD умножается на 2 и 1.5.
//  При переполнении выдается ~0u.
//  Для уменьшения фрагментации динамической
//  памяти учитывается размер системных данных
//  SIZE_SYS, добавляемых функцией realloc в
//  Borland C++ 3.1, 4.5.
//  Для оптимизации работы кэша L1 процесcоров
//  Pentuim SIZE_MOD задается как 64**n +/- 16.

#define SIZE_MOD (112)
#define SIZE_SYS (sizeof(int) * 2)

unsigned excalcsize (unsigned size)
{
  unsigned n = SIZE_MOD, k = 0;
  for (;; k = ~k, (k? (n <<= 1): (n += (n >> 1))))
  {
    n -= SIZE_SYS; if (n  >= size) break;
    n += SIZE_SYS; if ((int)n < 0) {n =~0u; break;}
  }
  return (n);
}

//  Объект - константа, содержащий
//  нулевой указатель и нулевое значение.

class   { void* e; unsigned len; } __EXNULL;