feisty meow concerns codebase 2.140
amorph.h
Go to the documentation of this file.
1#ifndef AMORPH_CLASS
2#define AMORPH_CLASS
3
4/*****************************************************************************\
5* *
6* Name : amorph *
7* Author : Chris Koeritz *
8* *
9*******************************************************************************
10* Copyright (c) 1989-$now By Author. This program is free software; you can *
11* redistribute it and/or modify it under the terms of the GNU General Public *
12* License as published by the Free Software Foundation; either version 2 of *
13* the License or (at your option) any later version. This is online at: *
14* http://www.fsf.org/copyleft/gpl.html *
15* Please send any updates to: fred@gruntose.com *
16\*****************************************************************************/
17
18#include "object_packers.h"
19
20#include <basis/astring.h>
21#include <basis/functions.h>
22#include <basis/contracts.h>
23#include <basis/guards.h>
24
26
55namespace structures {
56
57template <class contents>
58class amorph : protected basis::array<contents *>
59{
60public:
61 amorph(int elements = 0);
63
65
66 int elements() const { return this->length(); }
68
69 int valid_fields() const { return _fields_used; }
71
73 void adjust(int new_max);
75
79 void resize(int new_maximum = 0);
82 void reset() { this->resize(0); }
85 basis::outcome put(int field, const contents *data);
87
93 basis::outcome append(const contents *data);
95
98 basis::outcome operator += (const contents *data) { return append(data); }
100
102
104 const contents *get(int field) const;
106
108 contents *borrow(int field);
109
111 const contents *operator [] (int field) const { return get(field); }
113 contents *operator [] (int field) { return borrow(field); }
115 contents *acquire(int field);
117
124 basis::outcome clear(int field);
126
130 void clear_all();
133 basis::outcome zap(int start, int end);
135
143 basis::outcome insert(int position, int lines_to_add);
145
149 int find_empty(basis::outcome &o) const;
151
153 const contents *next_valid(int &field) const;
155
159 int find(const contents *to_locate, basis::outcome &o);
161
166 void swap_contents(amorph<contents> &other);
168
171private:
172 int _fields_used;
173
174 void check_fields(const char *where) const;
176
178 void set_nil(int start, int end);
179 // Puts NULL_POINTER in the indices between start and end.
183 // not to be used: amorphs should not be copied because it is intended that
184 // they support storing heavyweight objects that either have no copy
185 // constructors or have high-cost copy constructors.
186 amorph(const amorph &to_copy) {_fields_used = 0;}
187 amorph &operator = (const amorph &to_copy) { return *this; }
189};
190
192
193// these extensions are phrased as macros to avoid including the headers
194// necessary for compiling them. to use them, just put the macro name in
195// the file where the template is needed.
196
198
200
201template <class contents>
202void amorph_assign(amorph<contents> &to_assign,
203 const amorph<contents> &to_copy);
204
206
208
214template <class contents>
215void amorph_pack(basis::byte_array &packed_form, const amorph<contents> &to_pack);
216
218template <class contents>
219bool amorph_unpack(basis::byte_array &packed_form, amorph<contents> &to_unpack);
220
222template <class contents>
223int amorph_packed_size(const amorph<contents> &to_pack);
224
225// implementation for longer methods...
226
227//#define DEBUG_AMORPH
228 // uncomment to enable more testing, as well as complaints on errors.
229
230#undef static_class_name
231#define static_class_name() "amorph"
232 // used in bounds_halt macro.
233
234#undef AMO_ALERT
235#ifdef DEBUG_AMORPH
236 #include <basis/astring.h>
237 #define AMO_ALERT(a, b, c) basis::throw_error(basis::astring(a), basis::astring(func), basis::astring(b) + " -- " + c)
238 #define CHECK_FIELDS check_fields(func)
239#else
240 #define AMO_ALERT(a1, a2, a3) {}
241 #define CHECK_FIELDS { if (!func) {} }
242#endif
243
245
246template <class contents>
248: basis::array<contents *>(elements, NULL_POINTER, basis::array<contents *>::SIMPLE_COPY
249 | basis::array<contents *>::EXPONE | basis::array<contents *>::FLUSH_INVISIBLE),
250 _fields_used(0)
251{
252 FUNCDEF("constructor");
253 set_nil(0, elements - 1);
255}
256
257template <class contents>
259{
260 FUNCDEF("destructor");
262 clear_all();
263}
264
265template <class contents>
266void amorph<contents>::set_nil(int start, int end)
267{
268 for (int i = start; i <= end; i++)
270}
271
272template <class contents>
273void amorph<contents>::check_fields(const char *where) const
274{
275 FUNCDEF("check_fields");
276 int counter = 0;
277 for (int i = 0; i < elements(); i++)
278 if (basis::array<contents *>::get(i)) counter++;
279 if (_fields_used != counter) {
280 AMO_ALERT("amorph", basis::a_sprintf("check_fields for %s", where),
281 "error in _fields_used count");
282 }
283}
284
285template <class contents>
286void amorph<contents>::resize(int new_maximum)
287{
288 FUNCDEF("reset");
290 adjust(new_maximum);
291 clear_all();
292}
293
294template <class contents>
296{
297 FUNCDEF("clear_all");
299 for (int i = 0; i < elements(); i++) clear(i);
300}
301
302template <class contents>
304{
305 FUNCDEF("append");
307 adjust(elements() + 1);
308 return put(elements() - 1, (contents *)data);
309}
310
311template <class contents>
312const contents *amorph<contents>::get(int field) const
313{
314 FUNCDEF("get");
316 bounds_return(field, 0, elements() - 1, NULL_POINTER);
317 return basis::array<contents *>::observe()[field];
318}
319
320template <class contents>
321void amorph<contents>::adjust(int new_maximum)
322{
323 FUNCDEF("adjust");
325 if (new_maximum < 0) return; // bad input here.
326 int old_max = elements();
327 if (new_maximum == old_max) return; // nothing to do.
328 if (new_maximum < old_max) {
329 // removes the elements beyond the new size of the amorph.
330 zap(new_maximum, old_max - 1);
331 // we're done tuning it.
332 return;
333 }
334
335 // we get to here if we need more space than we used to.
336 int new_fields = new_maximum - old_max;
337
338 basis::array<contents *>::insert(old_max, new_fields);
339 for (int i = old_max; i < new_maximum; i++) {
341 }
342}
343
344template <class contents>
345basis::outcome amorph<contents>::insert(int position, int lines_to_add)
346{
347 FUNCDEF("insert");
349 bounds_return(position, 0, elements(), basis::common::OUT_OF_RANGE);
350 basis::outcome o = basis::array<contents *>::insert(position, lines_to_add);
351 if (o != basis::common::OKAY) return basis::common::OUT_OF_RANGE;
352 set_nil(position, position + lines_to_add - 1);
353 return basis::common::OKAY;
354}
355
356template <class contents>
357basis::outcome amorph<contents>::zap(int start_index, int end_index)
358{
359 FUNCDEF("zap");
361 bounds_return(start_index, 0, elements() - 1, basis::common::OUT_OF_RANGE);
362 bounds_return(end_index, 0, elements() - 1, basis::common::OUT_OF_RANGE);
363 if (end_index < start_index) return basis::common::OKAY;
364 for (int i = start_index; i <= end_index; i++) clear(i);
365 basis::outcome o = basis::array<contents *>::zap(start_index, end_index);
366 return (o == basis::common::OKAY? basis::common::OKAY : basis::common::OUT_OF_RANGE);
367}
368
369template <class contents>
370basis::outcome amorph<contents>::put(int field, const contents *data)
371{
372 FUNCDEF("put");
374 bounds_return(field, 0, elements() - 1, basis::common::OUT_OF_RANGE);
375 contents *to_whack = acquire(field);
376 delete to_whack;
377 if (data) {
378 basis::array<contents *>::access()[field] = (contents *)data;
379 _fields_used++;
380 }
381 return basis::common::OKAY;
382}
383
384template <class contents>
386{
387 FUNCDEF("find_empty");
389 if (_fields_used == elements()) { o = basis::common::IS_FULL; return 0; }
390 for (int i = 0; i < elements(); i++)
391 if (!basis::array<contents *>::get(i)) { o = basis::common::OKAY; return i; }
392 AMO_ALERT("amorph", "empty", "_fields_used is incorrect");
393 return basis::common::IS_FULL;
394}
395
396template <class contents>
397const contents *amorph<contents>::next_valid(int &field) const
398{
399 FUNCDEF("next_valid");
401 bounds_return(field, 0, elements() - 1, NULL_POINTER);
402 for (int i = field; i < elements(); i++)
404 field = i;
406 }
407 return NULL_POINTER;
408}
409
410template <class contents>
412{
413 FUNCDEF("clear");
415 return this->put(field, NULL_POINTER);
416}
417
418template <class contents>
419contents *amorph<contents>::acquire(int field)
420{
421 FUNCDEF("acquire");
423 contents *to_return = borrow(field);
424 if (to_return) {
425 _fields_used--;
427 }
428 return to_return;
429}
430
431template <class contents>
432int amorph<contents>::find(const contents *to_locate, basis::outcome &o)
433{
434 FUNCDEF("find");
436 if (!_fields_used) { o = basis::common::NOT_FOUND; return 0; }
437 for (int i = 0; i < elements(); i++) {
438 if (basis::array<contents *>::get(i) == to_locate) {
439 o = basis::common::OKAY;
440 return i;
441 }
442 }
443 o = basis::common::NOT_FOUND;
444 return 0;
445}
446
447template <class contents>
448contents *amorph<contents>::borrow(int field)
449{
450 FUNCDEF("borrow");
452 bounds_return(field, 0, elements() - 1, NULL_POINTER);
453 return basis::array<contents *>::access()[field];
454}
455
456template <class contents>
458{
459 FUNCDEF("swap_contents");
461 int hold_fields = _fields_used;
462 _fields_used = other._fields_used;
463 other._fields_used = hold_fields;
465}
466
467template <class contents>
469{
470 int parts_size = 0;
471 for (int i = 0; i < to_pack.elements(); i++) {
472 const contents *current = to_pack.get(i);
473 if (current) parts_size += current->packed_size();
474 }
475 return PACKED_SIZE_INT32 + parts_size;
476}
477
478template <class contents>
479void amorph_pack(basis::byte_array &packed_form, const amorph<contents> &to_pack)
480{
481 structures::attach(packed_form, to_pack.elements());
482 for (int i = 0; i < to_pack.elements(); i++) {
483 const contents *current = to_pack.get(i);
484 if (current) current->pack(packed_form);
485 }
486}
487
488template <class contents>
490{
491 to_unpack.reset();
492 int elem = 0;
493 if (!structures::detach(packed_form, elem)) return false;
494 for (int i = 0; i < elem; i++) {
495 contents *to_add = new contents;
496 if (!to_add->unpack(packed_form)) { delete to_add; return false; }
497 to_unpack.append(to_add);
498 }
499 return true;
500}
501
502template <class contents>
504 const amorph<contents> &to_copy)
505{
506 if (&to_assign == &to_copy) return;
507 to_assign.clear_all();
508 if (to_assign.elements() != to_copy.elements()) {
509 to_assign.zap(0, to_assign.elements() - 1);
510 to_assign.insert(0, to_copy.elements());
511 }
512 for (int i = 0; i < to_assign.elements(); i++) {
513 if (to_copy.get(i)) to_assign.put(i, new contents(*to_copy.get(i)));
514 else to_assign.put(i, (contents *)NULL_POINTER);
515 }
516}
517
518#undef static_class_name
519
520} //namespace.
521
522#endif
523
#define AMO_ALERT(a1, a2, a3)
Definition amorph.h:240
#define CHECK_FIELDS
Definition amorph.h:241
a_sprintf is a specialization of astring that provides printf style support.
Definition astring.h:440
Represents a sequential, ordered, contiguous collection of objects.
Definition array.h:54
outcome put(int index, const contents &to_put)
Stores an object at the index "index" in the array.
Definition array.h:834
outcome insert(int index, int new_indices)
Adds "new_indices" new positions for objects into the array at "index".
Definition array.h:803
const contents & get(int index) const
Accesses individual objects stored in "this" at the "index" position.
Definition array.h:372
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition array.h:175
const contents * observe() const
Returns a pointer to the underlying C array of data.
Definition array.h:172
int length() const
Returns the current reported length of the allocated C array.
Definition array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition array.h:769
void swap_contents(array< contents > &other)
Exchanges the contents of "this" and "other".
Definition array.h:452
A very common template for a dynamic array of bytes.
Definition byte_array.h:36
Outcomes describe the state of completion for an operation.
Definition outcome.h:31
int elements() const
the maximum number of elements currently allowed in this amorph.
Definition amorph.h:66
void resize(int new_maximum=0)
like adjust but doesn't keep existing contents.
Definition amorph.h:286
basis::outcome put(int field, const contents *data)
Enters an object into the field at index "field" in the amorph.
Definition amorph.h:370
const contents * operator[](int field) const
synonym for get.
Definition amorph.h:110
basis::outcome operator+=(const contents *data)
a synonym for append.
Definition amorph.h:97
amorph(int elements=0)
constructs an amorph capable of holding "elements" pointers.
Definition amorph.h:247
basis::outcome append(const contents *data)
puts "data" on the end of this amorph.
Definition amorph.h:303
basis::outcome zap(int start, int end)
Removes a range of indices from the amorph.
Definition amorph.h:357
void reset()
cleans out all of the contents.
Definition amorph.h:81
void swap_contents(amorph< contents > &other)
Exchanges the contents of "this" and "other".
Definition amorph.h:457
void adjust(int new_max)
Changes the maximum number of elements for this amorph.
Definition amorph.h:321
int find(const contents *to_locate, basis::outcome &o)
Searches the amorph for the contents specified.
Definition amorph.h:432
const contents * get(int field) const
Returns a constant pointer to the information at the index "field".
Definition amorph.h:312
int find_empty(basis::outcome &o) const
Returns the index of a free field if there are any.
Definition amorph.h:385
const contents * next_valid(int &field) const
Returns the contents of the next valid element at or after "field".
Definition amorph.h:397
basis::outcome insert(int position, int lines_to_add)
Adds "lines_to_add" indices to the amorph at the index "position".
Definition amorph.h:345
contents * acquire(int field)
Retrieves a "field" from the amorph, taking responsibility for it back.
Definition amorph.h:419
basis::outcome clear(int field)
Clears the contents of the field specified.
Definition amorph.h:411
contents * borrow(int field)
Returns a pointer to the information at the index "field".
Definition amorph.h:448
int valid_fields() const
Returns the number of fields that have non-null contents.
Definition amorph.h:69
void clear_all()
Clears every field in the amorph.
Definition amorph.h:295
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
#define bounds_return(value, low, high, to_return)
Verifies that "value" is between "low" and "high", inclusive.
Definition guards.h:48
bool append
Definition makedep.cpp:110
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55
void amorph_pack(basis::byte_array &packed_form, const amorph< contents > &to_pack)
support for packing an amorph into an array of bytes.
Definition amorph.h:479
int amorph_packed_size(const amorph< contents > &to_pack)
reports how large the packed form will be.
Definition amorph.h:468
void attach(byte_array &packed_form, const byte_array &to_attach)
Packs a byte_array "to_attach" into "packed_form".
void amorph_assign(amorph< contents > &to_assign, const amorph< contents > &to_copy)
This can be used when the templated object has a copy constructor.
Definition amorph.h:503
const int PACKED_SIZE_INT32
bool amorph_unpack(basis::byte_array &packed_form, amorph< contents > &to_unpack)
unpacks the amorph from an array of bytes.
Definition amorph.h:489
bool detach(byte_array &packed_form, byte_array &to_detach)
Unpacks a byte_array "to_detach" from "packed_form".