/*                                             -*- mode:C++; fill-column:100 -*-
  SFBHeap.cpp - The ancient K&R malloc, tweaked for packets
  Copyright (C) 2009 The Regents of the University of New Mexico.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  USA

  $Id$
*/

#ifndef SFBHEAP_H
#define SFBHEAP_H

#include "SFBFrame.h"
#include "SFBReactor.h"  /* For PacketHandler, ::reflex */

/**
 * A minimal heap memory allocator, based on the ancient K&R approach.
 *
 * There are 'malloc()' and 'free()' methods in this class, but since the size of the underlying
 * heap is fixed and only 1KB in size, it will typically be at least extremely frustrating, if not
 * simply impossible, to use these methods in a conventional 'general purpose dynamic memory'
 * programming style.
 *
 * Note that even a \code malloc(1) \endcode burns 16 bytes -- at _best_, no more than 64 non-empty
 * malloced blocks can be active at once!
 *
 * SBFHeap exists primarily to support SFBMemory, which provides a mechanism for temporary storage
 * of packets.
 */
class SFBHeap {

public:

  SFBHeap() ;

  void * malloc(u32 bytes) ;
  void free(void * packet) ;

  u8 * remember(const u8 * packet, bool unreadOnly = false, u8 sourceOverride = MAX_FACE_INDEX) ;
  u8 * rememberBytes(const u8 * bytePtr, u32 byteCount) ;
  void forget(u8 * packet) ;

  u8 * makePacket(u32 size) ;

  enum { 
    HEAP_SIZE_HEADERS = 1<<7,
    HEAP_SIZE_BYTES = HEAP_SIZE_HEADERS<<3,
    FREE_CHECK_BYTES = 0x5aa5,
    USED_CHECK_BYTES = 0xaa55
  };

private:

  union HeapHeader {
    double forAlignmentOnly;
    struct {
      u16 checkBytes;
      u16 size;                   /* in HeapHeader's, so 512KB max heap size */
      union {
        PacketHeader ph;
        HeapHeader * nextFree;
      } s;
    } f;
  };
  static void * initUsed(HeapHeader * h, u32 words) ;

  static u32 dataSize(HeapHeader * h) ;

  static bool putPacketByte(u8 * packet, const u8 byte) ;

  static void terminatePacket(u8 * packet) ;

  static u32 headers(u32 packetBytes) ;
  HeapHeader * findFit(u32 size) ;

  HeapHeader base;
  HeapHeader theHeap[HEAP_SIZE_HEADERS];
  HeapHeader * freePtr;

  HeapHeader * asHeader(u32 index) {
    return (HeapHeader*) &theHeap[index];
  }

#ifdef TEST_SFBHEAP
  friend class TestSFBHeap;
#endif

};

#endif  /* SFBHEAP_H */

