// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I #ifndef T_AR_WINH #define T_AR_WINH #include #include #include // add some defines so that we can work around the Mac's lack of // template capability. #define BIG_ARRAY(x) big_array #define BIG_2_ARRAY(x) big_2_array #define BIG_4_ARRAY(x) big_4_array // a class for large arrays. // pro: can be used with segmented architecture // has bounds checking built in // parsimonious with memory // con: slower than a simple array declaration template class big_array { boolean _auto_resize; const uint16 _n_elements_per_segment; uint32 _size, _n_segments; T** _tpp; public: // constructor big_array(const uint32 size = 0) : _n_elements_per_segment(64000 / sizeof(T)), _auto_resize(false) { _size = size; _n_segments = ((size ? size : (size + 1)) - 1) / _n_elements_per_segment + 1; heap_check(_tpp = new T* [_n_segments]); for (int n = 0; n < _n_segments; n++) heap_check(_tpp[n] = new T [_n_elements_per_segment]); } // copy constructor big_array(const big_array& p) : _n_elements_per_segment(p._n_elements_per_segment) { _auto_resize = p._auto_resize; _size = p._size; _n_segments = p._n_segments; heap_check(_tpp = new T* [_n_segments]); for (int n = 0; n < _n_segments; n++) heap_check(_tpp[n] = new T [_n_elements_per_segment]); for (n = 0; n < _n_segments; n++) for (int n1 = 0; n1 < _n_elements_per_segment; n1++) _tpp[n][n1] = p._tpp[n][n1]; } // destructor ~big_array(void) { for (int n = 0; n < _n_segments; n++) destroy_array(_tpp[n]); destroy_array(_tpp); } // switch on auto resizing inline void auto_resize(void) { _auto_resize = true; } // switch off auto resizing inline void no_auto_resize(void) { _auto_resize = false; } // set all elements of the array -- we can take advantage of the internal // structure to do this more quickly than otherwise possible void set_value(const T value) { for (int n = 0; n < _n_segments; n++) for (int n1 = 0; n1 < _n_elements_per_segment; n1++) _tpp[n][n1] = value; } // resize the array. The new array contains as much information as possible // from the old one. void resize(const uint32 new_size) { // allocate the new space const int _new_n_segments =((new_size ? new_size : (new_size + 1)) - 1) / _n_elements_per_segment + 1; T** _new_tpp; heap_check(_new_tpp = new T* [_new_n_segments]); for (uint32 n = 0; n < _new_n_segments; n++) heap_check(_new_tpp[n] = new T [_n_elements_per_segment]); const uint32 _elements_to_transfer = MIN(_size, (uint32)new_size); for (n = 0; n < _elements_to_transfer; n++) _new_tpp[n / _n_elements_per_segment][n % _n_elements_per_segment] = _tpp[n / _n_elements_per_segment][n % _n_elements_per_segment]; // now delete everything from the heap for (n = 0; n < _n_segments; n++) destroy_array(_tpp[n]); destroy_array(_tpp); // change internal values _size = new_size; _n_segments = _new_n_segments; _tpp = _new_tpp; } // retrieve an element T& operator[](const uint32 n) { if (n >= _size) then { if (!_auto_resize) then fatal_error("big_array index out of bounds"); else resize(MAX(2 * _size, (uint32)n)); } // perform explicit sanity check const uint16 index1 = n / _n_elements_per_segment, index2 = n % _n_elements_per_segment; if ((index1 >= _n_segments) || (index2 >= _n_elements_per_segment)) then fatal_error("failed sanity check in t_ar_win.h"); return _tpp[index1][index2]; } // return the current size inline uint32 size(void) const { return _size; } }; // a class for large multidimensional arrays template class big_multi_array { protected: int _n_dimensions; int* _dimensions; big_array _array; public: // constructor big_multi_array(const uint n_dimensions, ...) { va_list ap; va_start(ap, n_dimensions); _n_dimensions = n_dimensions; heap_check(_dimensions = new int [n_dimensions]); uint32 product = 1; for (int n = 0; n < n_dimensions; n++) { _dimensions[n] = va_arg(ap, const uint); product *= _dimensions[n]; } va_end(ap); _array.resize(product); } // copy constructor big_multi_array(const big_multi_array& p) { _n_dimensions = p._n_dimensions; heap_check(_dimensions = new int [_n_dimensions]); uint32 product = 1; for (int n = 0; n < _n_dimensions; n++) { _dimensions[n] = p._dimensions[n]; product *= _dimensions[n]; } _array.resize(product); // now copy the individual elements for (uint32 el = 0; el < product; el++) _array[el] = p._array[el]; } // destructor virtual ~big_multi_array(void) { destroy_array(_dimensions); } // big_multi_array = big_multi_array void operator=(big_multi_array param) { uint32 product = 1; for (int n = 0; n < _n_dimensions; n++) { _dimensions[n] = param._dimensions[n]; product *= _dimensions[n]; } _array.resize(product); // now copy the individual elements for (uint32 el = 0; el < product; el++) _array[el] = param._array[el]; } // set every element to zero void set_value(const T value) { _array.set_value(value); } // this is a dummy function; it is necessary because raw DOS uses it void freeze(void) { } // return a reference to an element. Unfortunately, for no reason of which I // am aware, one cannot declare an operator[](...). This is very slow (which // is a good reason not to use this template class unless one really needs // it). On the other hand, it is nice to be able to handle _all_ kinds of // multidimensional array with a single routine. T& element(const uint element, ...) { int* _elements; heap_check(_elements = new int [_n_dimensions]); va_list ap; va_start(ap, element); _elements[0] = element; for (int n = 1; n < _n_dimensions; n++) _elements[n] = va_arg(ap, const uint); va_end(ap); for (n = 0; n < _n_dimensions; n++) if ((_elements[n] < 0) || (_elements[n] >= _dimensions[n])) then fatal_error((DREstring)"Element out of range in big_multi_array; " + (DREstring)" dimension number " + DREstring10(n) + (DREstring)", value " + DREstring10(_elements[n]) + (DREstring)", bound " + DREstring10(_dimensions[n])); // we store in order of rightmost index contiguous uint32 index = 0; for (n = 0; n < _n_dimensions - 1; n++) index = (index + _elements[n]) * _dimensions[n + 1]; index += _elements[_n_dimensions - 1]; destroy_array(_elements); return _array[index]; } }; // faster versions for specific sizes template class big_2_array : public big_multi_array { public: big_2_array(const uint d1 = 0, const uint d2 = 0) : big_multi_array(2, d1, d2) { } // copy constructor big_2_array(const big_2_array& p) : big_multi_array(p) { } T& element(const uint element0, const uint element1) { if ((element0 > _dimensions[0]) || (element1 > _dimensions[1])) then fatal_error("Index out of bounds"); // we store in order of rightmost index contiguous return _array[((uint32)(element0) * _dimensions[1]) + element1]; } }; template class big_4_array : public big_multi_array { public: big_4_array(const uint d1 = 0, const uint d2 = 0, const uint d3 = 0, const uint d4 = 0) : big_multi_array(4, d1, d2, d3, d4) { } // copy constructor big_4_array(const big_4_array& p) : big_multi_array(p) { } T& element(const uint element0, const uint element1, const uint element2, const uint element3) const { if ((element0 > _dimensions[0]) || (element1 > _dimensions[1]) || (element2 > _dimensions[2]) || (element3 > _dimensions[3])) then fatal_error("Index out of bounds"); // we store in order of rightmost index contiguous uint32 index = (((uint32)element0 * _dimensions[1] + element1) * _dimensions[2] + element2) * _dimensions[3] + element3; return _array[index]; } }; #endif