1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code by Matt McCutchen, see the LICENSE file.
6 
7 #ifndef NUMBERLIKEARRAY_H
8 #define NUMBERLIKEARRAY_H
9 
10 #include <stdlib.h> // abort()
11 // Make sure we have NULL.
12 #ifndef NULL
13 #define NULL 0
14 #endif
15 
16 /* A NumberlikeArray<Blk> object holds a heap-allocated array of Blk with a
17  * length and a capacity and provides basic memory management features.
18  * BigUnsigned and BigUnsignedInABase both subclass it.
19  *
20  * NumberlikeArray provides no information hiding.  Subclasses should use
21  * nonpublic inheritance and manually expose members as desired using
22  * declarations like this:
23  *
24  * public:
25  *     NumberlikeArray< the-type-argument >::getLength;
26  */
27 template <class Blk>
28 class NumberlikeArray {
29 public:
30 
31 	// Type for the index of a block in the array
32 	typedef unsigned int Index;
33 	// The number of bits in a block, defined below.
34 	static const unsigned int N;
35 
36 	// The current allocated capacity of this NumberlikeArray (in blocks)
37 	Index cap;
38 	// The actual length of the value stored in this NumberlikeArray (in blocks)
39 	Index len;
40 	// Heap-allocated array of the blocks (can be NULL if len == 0)
41 	Blk *blk;
42 
43 	// Constructs a ``zero'' NumberlikeArray with the given capacity.
NumberlikeArray(Index c)44 	NumberlikeArray(Index c) : cap(c), len(0) {
45 		blk = (cap > 0) ? (new Blk[cap]) : NULL;
46 	}
47 
48 	/* Constructs a zero NumberlikeArray without allocating a backing array.
49 	 * A subclass that doesn't know the needed capacity at initialization
50 	 * time can use this constructor and then overwrite blk without first
51 	 * deleting it. */
NumberlikeArray()52 	NumberlikeArray() : cap(0), len(0) {
53 		blk = NULL;
54 	}
55 
56 	// Destructor.  Note that `delete NULL' is a no-op.
~NumberlikeArray()57 	~NumberlikeArray() {
58 		delete [] blk;
59 	}
60 
61 	/* Ensures that the array has at least the requested capacity; may
62 	 * destroy the contents. */
63 	void allocate(Index c);
64 
65 	/* Ensures that the array has at least the requested capacity; does not
66 	 * destroy the contents. */
67 	void allocateAndCopy(Index c);
68 
69 	// Copy constructor
70 	NumberlikeArray(const NumberlikeArray<Blk> &x);
71 
72 	// Assignment operator
73 	void operator=(const NumberlikeArray<Blk> &x);
74 
75 	// Constructor that copies from a given array of blocks
76 	NumberlikeArray(const Blk *b, Index blen);
77 
78 	// ACCESSORS
getCapacity() const79 	Index getCapacity()     const { return cap;      }
getLength() const80 	Index getLength()       const { return len;      }
getBlock(Index i) const81 	Blk   getBlock(Index i) const { return blk[i];   }
isEmpty() const82 	bool  isEmpty()         const { return len == 0; }
83 
84 	/* Equality comparison: checks if both objects have the same length and
85 	 * equal (==) array elements to that length.  Subclasses may wish to
86 	 * override. */
87 	bool operator ==(const NumberlikeArray<Blk> &x) const;
88 
operator !=(const NumberlikeArray<Blk> & x) const89 	bool operator !=(const NumberlikeArray<Blk> &x) const {
90 		return !operator ==(x);
91 	}
92 };
93 
94 /* BEGIN TEMPLATE DEFINITIONS.  They are present here so that source files that
95  * include this header file can generate the necessary real definitions. */
96 
97 template <class Blk>
98 const unsigned int NumberlikeArray<Blk>::N = 8 * sizeof(Blk);
99 
100 template <class Blk>
allocate(Index c)101 void NumberlikeArray<Blk>::allocate(Index c) {
102 	// If the requested capacity is more than the current capacity...
103 	if (c > cap) {
104 		// Delete the old number array
105 		delete [] blk;
106 		// Allocate the new array
107 		cap = c;
108 		blk = new Blk[cap];
109 	}
110 }
111 
112 template <class Blk>
allocateAndCopy(Index c)113 void NumberlikeArray<Blk>::allocateAndCopy(Index c) {
114 	// If the requested capacity is more than the current capacity...
115 	if (c > cap) {
116 		Blk *oldBlk = blk;
117 		// Allocate the new number array
118 		cap = c;
119 		blk = new Blk[cap];
120 		// Copy number blocks
121 		Index i;
122 		for (i = 0; i < len; i++)
123 			blk[i] = oldBlk[i];
124 		// Delete the old array
125 		delete [] oldBlk;
126 	}
127 }
128 
129 template <class Blk>
NumberlikeArray(const NumberlikeArray<Blk> & x)130 NumberlikeArray<Blk>::NumberlikeArray(const NumberlikeArray<Blk> &x)
131 		: len(x.len) {
132 	// Create array
133 	cap = len;
134 	blk = new Blk[cap];
135 	// Copy blocks
136 	Index i;
137 	for (i = 0; i < len; i++)
138 		blk[i] = x.blk[i];
139 }
140 
141 template <class Blk>
operator =(const NumberlikeArray<Blk> & x)142 void NumberlikeArray<Blk>::operator=(const NumberlikeArray<Blk> &x) {
143 	/* Calls like a = a have no effect; catch them before the aliasing
144 	 * causes a problem */
145 	if (this == &x)
146 		return;
147 	// Copy length
148 	len = x.len;
149 	// Expand array if necessary
150 	allocate(len);
151 	// Copy number blocks
152 	Index i;
153 	for (i = 0; i < len; i++)
154 		blk[i] = x.blk[i];
155 }
156 
157 template <class Blk>
NumberlikeArray(const Blk * b,Index blen)158 NumberlikeArray<Blk>::NumberlikeArray(const Blk *b, Index blen)
159 		: cap(blen), len(blen) {
160 	// Create array
161 	blk = new Blk[cap];
162 	// Copy blocks
163 	Index i;
164 	for (i = 0; i < len; i++)
165 		blk[i] = b[i];
166 }
167 
168 template <class Blk>
operator ==(const NumberlikeArray<Blk> & x) const169 bool NumberlikeArray<Blk>::operator ==(const NumberlikeArray<Blk> &x) const {
170 	if (len != x.len)
171 		// Definitely unequal.
172 		return false;
173 	else {
174 		// Compare corresponding blocks one by one.
175 		Index i;
176 		for (i = 0; i < len; i++)
177 			if (blk[i] != x.blk[i])
178 				return false;
179 		// No blocks differed, so the objects are equal.
180 		return true;
181 	}
182 }
183 
184 #endif
185