/**
 * PANDA 3D SOFTWARE
 * Copyright (c) Carnegie Mellon University.  All rights reserved.
 *
 * All use of this software is subject to the terms of the revised BSD
 * license.  You should have received a copy of this license along
 * with this source code in a file named "LICENSE."
 *
 * @file uniqueIdAllocator.h
 * @author schuyler
 * @date 2003-03-13
 */

#ifndef _UNIQUEIDALLOCATOR_H //[
#define _UNIQUEIDALLOCATOR_H

#include "pandabase.h"
#include "numeric_types.h"

/**
 * Manage a set of ID values from min to max inclusive.  The ID numbers that
 * are freed will be allocated (reused) in the same order.  I.e.  the oldest
 * ID numbers will be allocated.
 *
 * This implementation will use 4 bytes per id number, plus a few bytes of
 * management data.  e.g.  10,000 ID numbers will use 40KB.
 *
 * Also be advised that ID -1 and -2 are used internally by the allocator.  If
 * allocate returns IndexEnd (-1) then the allocator is out of free ID
 * numbers.
 *
 * There are other implementations that can better leverage runs of used or
 * unused IDs or use bit arrays for the IDs.  But, it takes extra work to
 * track the age of freed IDs, which is required for what we wanted.  If you
 * would like to kick around other implementation ideas, please contact
 * Schuyler.
 */
class EXPCL_PANDA_PUTIL UniqueIdAllocator {
PUBLISHED:
  explicit UniqueIdAllocator(uint32_t min=0, uint32_t max=20);
  ~UniqueIdAllocator();

  uint32_t allocate();
  void initial_reserve_id(uint32_t id);

  void free(uint32_t index);
  PN_stdfloat fraction_used() const;

  void output(std::ostream &out) const;
  void write(std::ostream &out) const;

public:
  static const uint32_t IndexEnd;
  static const uint32_t IndexAllocated;

protected:
  // _table stores an array of _size words, corresponding to each allocatable
  // id.

  // For each free id, the table entry at the corresponding index contains the
  // index number of the next free id, thus defining a chain of free id's.
  // The last element of the chain contains IndexEnd.

  // For an allocated id, the table entry at the corresponding index contains
  // IndexAllocated.
  uint32_t *_table;

  // The minimum and maximum as passed to the constructor.
  uint32_t _min;
  uint32_t _max;

  // This is the head of the free chain: as elements are allocated, they are
  // taken from _table[_next_free].  If the free chain is empty, _next_free ==
  // IndexEnd.
  uint32_t _next_free;

  // This is the tail of the free chain: as elements are freed, they are
  // stored in _table[_last_free].  Normally, _table[_last_free] is the end of
  // the free chain, unless the free chain is empty.
  uint32_t _last_free;

  // The total number of elements in _table.
  uint32_t _size;

  // The number of free elements in _table.
  uint32_t _free;
};

#endif //]
