/*ident	"@(#)cls4:src/Block.h	1.1" */
/*******************************************************************************
 
C++ source for the C++ Language System, Release 3.0.  This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.

Copyright (c) 1991 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T.  All Rights Reserved.

THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc.  The copyright notice above does not evidence
any actual or intended publication of such source code.

*******************************************************************************/
#ifndef BLOCK_H
#define BLOCK_H 1
#ifndef GENERICH
#include <generic.h>
#endif

#define Block(T)name2(Block_,T)

#define Blockdeclare(T)							\
									\
class Block(T) {							\
public:									\
	unsigned size() const { return n; }				\
	unsigned size(unsigned k) { move(new T[k], k); return n; }	\
	Block(T)() { n = 0; p = 0; }					\
	Block(T)(unsigned k) { n = 0; p = 0; size(k); }			\
	Block(T)(const Block(T)& b) { copy(b); }			\
	~Block(T)() { delete[n] p; }					\
	Block(T)& operator=(const Block(T)& b) {			\
		delete[n] p;						\
		copy(b);						\
		return *this;						\
	}								\
	operator T*() { return p; }					\
	operator const T*() const { return p; }				\
	T* end() { return p + n; }					\
	const T* end() const { return p + n; }				\
	T& operator[](int i) { return p[i]; }				\
	const T& operator[](int i) const { return p[i]; }		\
	int reserve(unsigned k) { return k<n || grow(k); }		\
	void swap(Block(T)& b);						\
private:								\
	T* p;								\
	unsigned n;							\
	void move(T*, unsigned);					\
	void transfer(T*, unsigned);					\
	void clear(T*, unsigned);					\
	void copy(const Block(T)&);					\
	unsigned grow(unsigned);					\
};									\
									\

#define Blockimplement(T)						\
									\
static T name2(Block(T),_def);						\
									\
/* Clear k elements starting at v */					\
void									\
Block(T)::clear(T* v, unsigned k)					\
{									\
	register T* p = v;						\
	register T* lim = v + k;					\
	while (p < lim)							\
		*p++ = name2(Block(T),_def);				\
}									\
									\
/* This Block was uninitialized, is now a copy of b */			\
void									\
Block(T)::copy(const Block(T)& b)					\
{									\
	p = new T[b.n];							\
	if (p) {							\
		n = b.n;						\
		transfer(b.p, n);					\
	} else								\
		n = 0;							\
}									\
									\
/* Grow this Block by 1.5 until it can contain at least k+1 */		\
unsigned								\
Block(T)::grow(unsigned k)						\
{									\
	unsigned nn = n;						\
	if (nn == 0)							\
		nn++;							\
	while (nn <= k)							\
		nn += (nn >> 1) + 1;					\
	T* np = new T[nn];						\
	if (!np) {							\
		nn = k+1;						\
		np = new T[nn];						\
	}								\
	move(np, nn);							\
	return n;							\
}									\
									\
/* Transfer len (or fewer) elements into this Block. */			\
void									\
Block(T)::transfer(T* source, unsigned len)				\
{									\
	register T* plim;						\
	register T* pp = p;						\
	register T* q = source;						\
									\
	if (n > len) {							\
		plim = p + len;						\
		clear(plim, n - len);					\
	} else								\
		plim = p + n;						\
									\
	while (pp < plim)						\
		*pp++ = *q++;						\
}									\
									\
/*									\
 * The contents of this Block now live in memory starting at np		\
 * If np is 0, null out this Block.					\
 */									\
void									\
Block(T)::move(T* np, unsigned nn)					\
{									\
	T* oldp = p;							\
	unsigned oldn = n;						\
	p = np;								\
	if (np) {							\
		n = nn;							\
		transfer(oldp, oldn);					\
	} else								\
		n = 0;							\
	delete[oldn] oldp;						\
}									\
									\
/* Exchange the contents of this Block with another Block */		\
void									\
Block(T)::swap(Block(T)& b)						\
{									\
	T* bp = b.p;							\
	unsigned bn = b.n;						\
	b.p = p;							\
	b.n = n;							\
	p = bp;								\
	n = bn;								\
}									\
									\


#endif
