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 
55 namespace structures {
56 
57 template <class contents>
58 class amorph : protected basis::array<contents *>
59 {
60 public:
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);
81 
82  void reset() { this->resize(0); }
84 
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); }
114 
115  contents *acquire(int field);
117 
124  basis::outcome clear(int field);
126 
130  void clear_all();
132 
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 
171 private:
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 
201 template <class contents>
202 void amorph_assign(amorph<contents> &to_assign,
203  const amorph<contents> &to_copy);
204 
206 
208 
214 template <class contents>
215 void amorph_pack(basis::byte_array &packed_form, const amorph<contents> &to_pack);
216 
218 template <class contents>
219 bool amorph_unpack(basis::byte_array &packed_form, amorph<contents> &to_unpack);
220 
222 template <class contents>
223 int 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 
246 template <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);
254  CHECK_FIELDS;
255 }
256 
257 template <class contents>
259 {
260  FUNCDEF("destructor");
261  CHECK_FIELDS;
262  clear_all();
263 }
264 
265 template <class contents>
266 void amorph<contents>::set_nil(int start, int end)
267 {
268  for (int i = start; i <= end; i++)
270 }
271 
272 template <class contents>
273 void 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 
285 template <class contents>
286 void amorph<contents>::resize(int new_maximum)
287 {
288  FUNCDEF("reset");
289  CHECK_FIELDS;
290  adjust(new_maximum);
291  clear_all();
292 }
293 
294 template <class contents>
296 {
297  FUNCDEF("clear_all");
298  CHECK_FIELDS;
299  for (int i = 0; i < elements(); i++) clear(i);
300 }
301 
302 template <class contents>
304 {
305  FUNCDEF("append");
306  CHECK_FIELDS;
307  adjust(elements() + 1);
308  return put(elements() - 1, (contents *)data);
309 }
310 
311 template <class contents>
312 const contents *amorph<contents>::get(int field) const
313 {
314  FUNCDEF("get");
315  CHECK_FIELDS;
316  bounds_return(field, 0, elements() - 1, NULL_POINTER);
317  return basis::array<contents *>::observe()[field];
318 }
319 
320 template <class contents>
321 void amorph<contents>::adjust(int new_maximum)
322 {
323  FUNCDEF("adjust");
324  CHECK_FIELDS;
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 
344 template <class contents>
345 basis::outcome amorph<contents>::insert(int position, int lines_to_add)
346 {
347  FUNCDEF("insert");
348  CHECK_FIELDS;
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 
356 template <class contents>
357 basis::outcome amorph<contents>::zap(int start_index, int end_index)
358 {
359  FUNCDEF("zap");
360  CHECK_FIELDS;
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 
369 template <class contents>
370 basis::outcome amorph<contents>::put(int field, const contents *data)
371 {
372  FUNCDEF("put");
373  CHECK_FIELDS;
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 
384 template <class contents>
386 {
387  FUNCDEF("find_empty");
388  CHECK_FIELDS;
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 
396 template <class contents>
397 const contents *amorph<contents>::next_valid(int &field) const
398 {
399  FUNCDEF("next_valid");
400  CHECK_FIELDS;
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 
410 template <class contents>
412 {
413  FUNCDEF("clear");
414  CHECK_FIELDS;
415  return this->put(field, NULL_POINTER);
416 }
417 
418 template <class contents>
419 contents *amorph<contents>::acquire(int field)
420 {
421  FUNCDEF("acquire");
422  CHECK_FIELDS;
423  contents *to_return = borrow(field);
424  if (to_return) {
425  _fields_used--;
427  }
428  return to_return;
429 }
430 
431 template <class contents>
432 int amorph<contents>::find(const contents *to_locate, basis::outcome &o)
433 {
434  FUNCDEF("find");
435  CHECK_FIELDS;
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 
447 template <class contents>
448 contents *amorph<contents>::borrow(int field)
449 {
450  FUNCDEF("borrow");
451  CHECK_FIELDS;
452  bounds_return(field, 0, elements() - 1, NULL_POINTER);
453  return basis::array<contents *>::access()[field];
454 }
455 
456 template <class contents>
458 {
459  FUNCDEF("swap_contents");
460  CHECK_FIELDS;
461  int hold_fields = _fields_used;
462  _fields_used = other._fields_used;
463  other._fields_used = hold_fields;
465 }
466 
467 template <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 
478 template <class contents>
479 void 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 
488 template <class contents>
489 bool amorph_unpack(basis::byte_array &packed_form, amorph<contents> &to_unpack)
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 
502 template <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 * observe() const
Returns a pointer to the underlying C array of data.
Definition: array.h:172
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
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
const contents * operator[](int field) const
synonym for get.
Definition: amorph.h:110
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
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:57
#define bounds_return(value, low, high, to_return)
Verifies that "value" is between "low" and "high", inclusive.
Definition: guards.h:48
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".