view anagram/support/agstack.cpp @ 4:bebb2ba69e1d

maybe help with getting tex to fail properly on error
author David A. Holland
date Sat, 18 Apr 2020 17:12:17 -0400
parents 13d2b8934445
children
line wrap: on
line source

/**********************************************************

The AnaGram Class Library

The AgStackStorage Class
Copyright 1997 Parsifal Software. All Rights Reserved.
See the file COPYING for license and usage terms.

***********************************************************/

#include "agstack.h"
#include "assert.h"

// Caution - enabling this causes AG to core before anything is logged
//#define INCLUDE_LOGGING
#include "log.h"


static int bytesAllocated = 0;
//int constructorCalls = 0;
//int copyConstructorCalls = 0;
//int destructorCalls = 0;

AgStackStorage::AgStackStorage(const unsigned quantum_,
			       const unsigned logSize_,
			       const unsigned bsLogSize_)
  : buffer(malloc((unsigned)(quantum_ * (1<< logSize_))))
  , bufferStack(0)
  , count(0)
  , usage(1)
  , quantum((unsigned short) quantum_)
  , bufferSize((unsigned short) (1 << logSize_))
  , mask((unsigned short) (bufferSize - 1))
  , index(0)
  , logSize((unsigned char) logSize_)
  , bsLogSize((unsigned char) bsLogSize_)
{
  LOGSECTION("AgStackStorage::AgStackStorage");
  bytesAllocated += quantum * bufferSize;
  //LOGV(bytesAllocated) LCV(quantum * bufferSize);
}

void *AgStackStorage::push() {
  if (index >= bufferSize) {
    if (bufferStack == 0) {
      bufferStack = new AgStack<void *>(bsLogSize);
    }
    bufferStack->push(buffer);
    //buffer = ::operator new(quantum*bufferSize);
    buffer = malloc(quantum*bufferSize);
    LOGS("AgStackStorage::push");
    bytesAllocated += quantum*bufferSize;
    //LOGV(bytesAllocated) LCV(quantum*bufferSize);
    index = 0;
  }
  count++;
  return (char *)buffer+quantum*index++;
}

void *AgStackStorage::pop() {
  assert(count > 0);
  if (index == 0) {
    //delete buffer;
    free(buffer);
    LOGS("AgStackStorage::pop");
    bytesAllocated -= quantum*bufferSize;
    //LOGV(bytesAllocated) LCV(quantum * bufferSize);
    buffer = bufferStack->pop();
    if (bufferStack->size() == 0) {
      delete bufferStack;
      bufferStack = 0;
    }
    index = bufferSize;
  }
  count--;
  return (char *)buffer+quantum*(--index);
}

AgStackStorage &AgStackStorage::discardData(unsigned n) {
  assert(count >= n);
  unsigned k = (unsigned) index < n ? index : n;

  LOGSECTION("AgStackStorage::discardData");
  LOGV(n) LCV(count) LCV(index) LCV(k) LCV((int) buffer) LCV(logSize);

  count -= k;
  index -= (unsigned short) k;
  if (count == 0) {
    return *this;
  }
  n -= k;
  if (index == 0 && bufferStack != 0) {
    //delete buffer;
    free(buffer);
    k = (n-1) >> logSize;
    LOGV(k);
    //if (k > 1) {
      //k--;
    if (k) {
      bufferStack->discardData(k);
      k <<= logSize;
      n -= k;
      count -= k;
    }
    LOGV(k) LCV(n) LCV(count);
    buffer = bufferStack->pop();
    if (bufferStack->size() == 0) {
      delete bufferStack;
      bufferStack = 0;
    }
    index = bufferSize;
  }
  count -= n;
  index -= (unsigned short) n;
  LOGV(n);
  LOGV(count);
  LOGV(index);
  LOGV(k);
  return *this;
}

void *AgStackStorage::locate(const unsigned n) const {
#ifdef INCLUDE_LOGGING
  if (n >= count) {
    LOGSECTION("AgStackStorage::locate");
    LOGV(n);
    LOGV(count);
  }
#endif
  assert(n < count);
  if (bufferStack == 0) {
    return (char *) buffer + quantum*n;
  }
  unsigned q = n >> logSize;
  //void *buf = (q >= bufferStack->size()) ? buffer : (*bufferStack)[q];
  //return (char *)buf + quantum * (n&mask);
  if (q < bufferStack->size()) {
    return (char *)(*bufferStack)[q] + quantum * (n&mask);
  }
  return (char *) buffer + quantum * (n&mask);

}

AgStackStorage::~AgStackStorage() {
  LOGSECTION("AgStackStorage::~AgStackStorage");
  //delete buffer;
  free(buffer);
  bytesAllocated -= quantum*bufferSize;
  //LOGV(bytesAllocated) LCV(quantum*bufferSize);
  if (bufferStack) {
    int n = bufferStack->size();
    LOGV(n);
    while (n--) {
      // XXX. I believe this should be free(), not delete.
      delete (char *)bufferStack->pop();
    }
    delete bufferStack;
  }
}

AgStackStorage &AgStackStorage::discardData() {
  discardData(count);
  return *this;
}