Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
BlkArr.h
Go to the documentation of this file.
1#ifndef BLKARR_H
2#define BLKARR_H
3/*
4Blocked array, the compromise between efficiency of access by indexing
5and efficiency of size increasing. In addition it is sometimes
6important that the size increasing is performed without copying of elements.
7The information is allocated by several blocks, as many as needed.
8So this is some intermediate case between the ordinary array and the list.
9In the array the information is kept in one block, whereas in the list each
10element is saved individually. Here, in the blocked array, the elements are
11grouped, but there is no requirement to keep them in a single block.
12Consequently, when the reserved space is exhausted, the next block is created.
13It is convenient to establish its size as no less then the total size of
14already allocated blocks. Then the number of blocks will grouth much slower
15than the array size, and the efficient indexing will be preserved.
16To avoid memory limits, the total " default" increment should be limited,
17here by parameter
18const long max_size_of_extra_increment = 1000000; // in bytes
19
20That means that the simple model used in DynLinArr and consisted in
21characterising the array by only one parameter, its physical size,
22occurs inappropriate for the blocked array. The physical size of blocked array
23may be more that its logical size. Not only the part of block can be unused,
24but the total block can be unused as well. This may happen as result of
25array decreasing and intention to preserve something like histeresis.
26At decreasing of such array it is reasonable to preserve the "next" allocated
27block. That means that if before decrease the array was kept in, for example,
285 blocks, and after decrease the array is kept in 3 blocks, the 4 block
29is kept allocated to assure quick increase in future.
30
31If the order of value of required memory is known, it is reasonable to
32allocate the first block with corresponding size, so as to optimise further
33operations. If the array is empty logically as well as physically,
34for example at or right after the initialization with zero size,
35this can be done with ordinary call put_qel(number of elements).
36But the initializes both the physical and the logical size,
37whereas the latter is not always necessary.
38In addition, if this call is made for the array that is not physically empty,
39the allocation of this array as a single block is not guaranteed due to
40mentioned histeresis. Then the only choice to allocate the physical size of
41the first block only (not the logucal size) is the use of call
42void BlkArr::allocate_block(long fqel).
43Note: if array has contained something, this call clears it.
44So actually it always allocates the first block and makes it empty.
45This call inialize only the physical structure, and lefts the logical size
46zero. If it need to allocate the logical size as well,
47use double calls:
48void BlkArr::allocate_block(long fqel).
49void BlkArr::put_qel(long fqel).
50
51This is the sence.
52
53
54
55Copyright (c) 2003 I. B. Smirnov
56
57The file can be used, copied, modified, and distributed
58according to the terms of GNU Lesser General Public License version 2.1
59as published by the Free Software Foundation,
60and provided that the above copyright notice, this permission notice,
61and notices about any modifications of the original text
62appear in all copies and in supporting documentation.
63The file is provided "as is" without express or implied warranty.
64*/
65//#include <CLHEP/Alist/AList.h>
68//#include "math/minmax.h"
72//#include "wcpplib/math/DoubleAc.h"
73
74//#define DEBUG_BLKARR // make some print
75
76const long max_size_of_extra_increment = 1000000; // in bytes
77
78#ifndef DONT_USE_ABSPTR
79template <class T>
80class BlkArr : public RegPassivePtr {
81#else
82template <class T>
83class BlkArr {
84#endif
85 public:
86 BlkArr(void) : qel(0), la(), size_of_element(sizeof(T)) { ; }
87 explicit BlkArr(long fqel)
88 : qel(fqel), la(DynLinArr<T>(0)), size_of_element(sizeof(T)) {
89 if (qel > 0) la.get_first_node()->el.put_qel(qel);
90 }
91 BlkArr(long fqel, const T& val)
92 : qel(fqel), la(DynLinArr<T>(0)), size_of_element(sizeof(T)) {
93 if (qel > 0) la.get_first_node()->el.put_qel(qel, val);
94 }
95 BlkArr(long fqel, const T* ar, ArgInterp_Arr t)
96 : qel(fqel), la(DynLinArr<T>(0)), size_of_element(sizeof(T)) {
97 if (qel > 0)
98 // la.get_first_node()->el.put_qel(qel, ar, interp_as_arr); error
99 la.get_first_node()->el.pilfer(DynLinArr<T>(qel, ar, t));
100 }
101 // const T* ar is array here (of course).
102 // ArgInterp_Arr serves to distinguish this
103 // from previous constructor when second argument
104 // does not coincide with T but can be converted to it.
105 // Typical example is when T is double and second argument is 0.
106 // It is assumed that 0 should be converted to 0.0 and previous
107 // constructor should be called. But in practice (Red Hat Linux 6.0)
108 // the compiler says
109 // call of overloaded `DynLinArr(int &, int)' is ambiguous.
110 // I don't know whether this is error of particular compiler or
111 // general problem. But the third dummy argument is anyway convenient
112 // to distringuish these cases.
114#ifdef DEBUG_BLKARR
115 mcout << "BlkArr<T>& operator=(const BlkArr<T>& f) is called\n";
116#endif
117 if (this != &f) {
118 qel = f.qel;
119 size_of_element = f.size_of_element;
120 la = f.la;
121 }
122 return *this;
123 }
124 //BlkArr( BlkArr<T>& f):qel(0), la() {*this=f;}
126 :
127#ifndef DONT_USE_ABSPTR
128 RegPassivePtr(),
129#endif
130 qel(0),
131 la() {
132#ifdef DEBUG_BLKARR
133 mcout << "BlkArr(const BlkArr<T>& f) is working\n";
134#endif
135 *this = f;
136 }
138 : qel(f.qel), size_of_element(f.size_of_element), la(f.la, steal) {
139#ifdef DEBUG_BLKARR
140 mcout << "BlkArr( BlkArr<T>& f, Pilfer) is working\n";
141#endif
142 f.qel = 0;
143 f.size_of_element = 0;
144 }
146#ifdef DEBUG_BLKARR
147 mcout << "BlkArr::pilfer is called\n";
148#endif
149 if (this != &f) {
150 if (qel != 0) {
151 if (f.qel != 0) {
152 mcerr << "ERROR in BlkArr::pilfer(...):\n";
153 mcerr << "Both the destination and source arrays are not empty\n";
154 // For explanations why it is dengerous, see similar function
155 // of ActivePtr.
156 spexit(mcerr);
157 } else {
158 la.clear();
159 size_of_element = 0;
160 qel = 0;
161 }
162 }
163 qel = f.qel;
164 size_of_element = f.size_of_element;
165 la.pilfer(f.la);
166 f.qel = 0;
167 f.size_of_element = 0;
168 }
169 }
170 BlkArr& assignAll(const T& f) {
171 long n;
172 for (n = 0; n < qel; n++)
173 operator[](n) = f;
174 return *this;
175 }
176 T& operator[](long n);
177 const T& operator[](long n) const;
178 T& last_el(void);
179 const T& last_el(void) const;
180
181 long get_qel(void) const { return qel; }
182 void put_qel(long fqel);
183 //void put_qel(long fqel, const T* val, int s);
184 // creates array with size fqel
185 // If old array existed, then
186 // If it was less than fqel, it all is copied to new array
187 // and the other elements either assigned *val or
188 // remains not inited.
189 // else its fqel part is copyed to new array.
190 // s serves to distinguish this
191 // from previous constructor when second argument
192 // does not coincide with T but can be converted to it.
193 // Attention!, val is an element, this is assimetry with contructor,
194 // in which ar is an array.
195
196 //void put_qel(long fqel, const T& val){put_qel(fqel, &val, 1);} later
197 void increment(void) {
198 long q = qel + 1;
199 put_qel(q);
200 }
201 void decrement(void) {
202 long q = qel - 1;
203 put_qel(q);
204 }
205 void append(const T& val) {
206 increment();
207 operator[](qel - 1) = val;
208 }
209 //void increment(const T* val=NULL)
210 // { check(); long q=qel+1; put_qel(q, *val); }
211 //void increment(const T& val)
212 // { check(); long q=qel+1; put_qel(q, *val); }
213 //void check(void) const;
214
215 /*
216 void print(std::ostream& file, long qpr) const
217 {
218 Ifile<<"DynLinArr<T>: qel="<<get_qel()<<" qpr="<<qpr<<'\n';
219 long n;
220 indn.n+=2;
221 for( n=0; n<qpr; n++)
222 {
223 Ifile<<"n="<<n<<" el[n]="<<this->DynLinArr<T>::operator[](n)<<'\n';
224 }
225 indn.n-=2;
226 }
227 */
228
229 //~BlkArr() { if(el != NULL) delete[] el; }
230 void print_struct(std::ostream& file) const;
231 void allocate_block(long fqel) // allocates first blocks but qel = 0
232 {
233 la.clear();
234 qel = 0;
235 put_qel(fqel);
236 qel = 0;
237 }
238 void clear(void) {
239 la.clear();
240 qel = 0;
241 }
242#ifndef DONT_USE_ABSPTR
244#endif
245 virtual ~BlkArr(void) {}
246
247 private:
248 PILF_MUTABLE long qel; // number of elements currently activated
249 PILF_MUTABLE AbsList<DynLinArr<T> > la; // list of arrays
250 PILF_MUTABLE long size_of_element;
251#ifdef USE_REPLACE_ALLOC
253#endif
254};
255
256template <class T> T& BlkArr<T>::operator[](long n) {
257 if (n < 0 || n >= qel) {
258 mcerr << "T& BlkArr::operator[](long n): n is out of bounds, n=" << n
259 << " qel=" << qel << '\n';
260 spexit(mcerr);
261 }
262 long q;
264 do {
265 if ((q = aln->el.get_qel()) > n)
266 return aln->el.acu(n);
267 else
268 n -= q;
269 aln = aln->get_next_node();
270 } while (aln != NULL);
271 mcerr << "T& BlkArr::operator[](long n): should never happen, n=" << n
272 << " qel=" << qel << '\n';
273 spexit(mcerr);
274#ifdef INS_CRETURN // Insert calming return
275 return aln->el[0]; // to quiet Microsoft Visial Studio compiler against
276 // "not all control paths return a value"
277#endif
278}
279
280template <class T> const T& BlkArr<T>::operator[](long n) const {
281 if (n < 0 || n >= qel) {
282 mcerr << "const T& BlkArr::operator[](long n): n is out of bounds, n=" << n
283 << " qel=" << qel << '\n';
284 spexit(mcerr);
285 }
286 long q;
288 do {
289 if ((q = aln->el.get_qel()) > n)
290 return aln->el.acu(n);
291 else
292 n -= q;
293 aln = aln->get_next_node();
294 } while (aln != NULL);
295 mcerr << "T& BlkArr::operator[](long n): should never happen, n=" << n
296 << " qel=" << qel << '\n';
297 spexit(mcerr);
298#ifdef INS_CRETURN // Insert calming return
299 return aln->el[0]; // to quiet Microsoft Visial Studio compiler against
300 // "not all control paths return a value"
301#endif
302}
303
304template <class T> T& BlkArr<T>::last_el(void) {
305 if (qel <= 0) {
306 mcerr << "T& BlkArr::last_el(): no elements in array\n"
307 << " qel=" << qel << '\n';
308 spexit(mcerr);
309 }
310 long q;
312 long n = qel - 1;
313 do {
314 if ((q = aln->el.get_qel()) > n)
315 return aln->el.acu(n);
316 else
317 n -= q;
318 aln = aln->get_next_node();
319 } while (aln != NULL);
320 mcerr << "T& BlkArr::::last_el(): should never happen, n=" << n
321 << " qel=" << qel << '\n';
322 spexit(mcerr);
323#ifdef INS_CRETURN // Insert calming return
324 return aln->el[0]; // to quiet Microsoft Visial Studio compiler against
325 // "not all control paths return a value"
326#endif
327}
328
329template <class T> const T& BlkArr<T>::last_el(void) const {
330 if (qel <= 0) {
331 mcerr << "const T& BlkArr::last_el(): no elements in array\n"
332 << " qel=" << qel << '\n';
333 spexit(mcerr);
334 }
335 long q;
337 long n = qel - 1;
338 do {
339 if ((q = aln->el.get_qel()) > n)
340 return aln->el.acu(n);
341 else
342 n -= q;
343 aln = aln->get_next_node();
344 } while (aln != NULL);
345 mcerr << "T& BlkArr::::last_el(): should never happen, n=" << n
346 << " qel=" << qel << '\n';
347 spexit(mcerr);
348#ifdef INS_CRETURN // Insert calming return
349 return aln->el[0]; // to quiet Microsoft Visial Studio compiler against
350 // "not all control paths return a value"
351#endif
352}
353
354template <class T> void BlkArr<T>::put_qel(long fqel) {
355 //mcout<<"BlkArr<T>::put_qel: fqel="<<fqel<<'\n';
356 if (fqel == qel) return;
357 /*
358 if(fqel == 0)
359 {
360 qel = 0;
361 la.clear();
362 }
363 else
364 {
365 */
366 //long n;
368 if (aln == NULL) {
369 la.insert_after(NULL, DynLinArr<T>(0));
370 la.get_first_node()->el.put_qel(fqel);
371 qel = fqel;
372 return;
373 } else {
374 if (fqel > qel) // the case of increase
375 {
376 long fqel_res = fqel; // space to reserve
377 // fqel_res should be more than fqel
378 // But remember, both are the total number of elements, not the increase
379 if (fqel_res < 2 * qel) // then consider more space to reserve
380 {
381 long ex = 2 * qel * size_of_element; // compute the memory expense
382 if (ex < max_size_of_extra_increment) // check whether it is not large
383 fqel_res = 2 * qel; // OK
384 else { // No, too large
385 long q = max_size_of_extra_increment / size_of_element; //less number
386 if (q <= 0) q = 1; // 1 at least
387 if (fqel_res - qel < q) fqel_res = qel + q; // increase
388 }
389 }
390 long q;
391 long left_old_qel = qel;
392 long left_new_qel = fqel;
393 long left_new_qel_res = fqel_res;
394 //Iprintn(mcout, left_new_qel);
395 //Iprintn(mcout, left_new_qel_res);
397 do {
398 q = aln->el.get_qel();
399 //Iprintn(mcout, q);
400 //Iprintn(mcout, left_old_qel);
401 //Iprintn(mcout, left_new_qel);
402 if (q >= left_old_qel) // this node, there is space
403 {
404 if (q >= left_new_qel) // that's enough, nothing to do
405 { // and no reservation additional space
406 qel = fqel;
407 return;
408 } else // No, the new requested space is larger then the available
409 { // in the current node. But there may be next ones inited
410 // already
411 left_new_qel -= q;
412 left_new_qel_res -= q;
413 AbsListNode<DynLinArr<T> >* aln1; // pointer to block
414 while (
415 (aln1 = aln->get_next_node()) !=
416 NULL) { // scanning next blocks, which may be present already
417 aln = aln1;
418 q = aln->el.get_qel();
419 if (q >= left_new_qel) // Good, existing space is enogh
420 {
421 qel = fqel;
422 return;
423 }
424 left_new_qel -= q;
425 left_new_qel_res -= q;
426 } // No, is not enough
427 // then make new node with reservation
428 la.insert_after(aln, DynLinArr<T>(0));
429 la.get_last_node()->el.put_qel(left_new_qel_res);
430 qel = fqel;
431 //Iprintn(mcout, qel);
432 return;
433 }
434 }
435 left_old_qel -= q;
436 left_new_qel -= q;
437 aln = aln->get_next_node();
438 } while (aln != NULL);
439 mcout << "BlkArr<T>::put_qel: should never happen\n";
440 } else // the case of decrease
441 {
442 long q;
443 long left_old_qel = qel;
444 long left_new_qel = fqel;
446 do {
447 q = aln->el.get_qel();
448 if (q >= left_new_qel) // this node, there is space
449 {
450 // initialize by dummy constructor so as to get rid of garbage,
451 // that is of elements at the end of this block
452 long n;
453 for (n = left_new_qel; n < q; n++) {
454 aln->el[n] = T();
455 }
456 left_old_qel -= q;
457 //left_new_qel -= q;
459 if (aln1 != NULL) // so preserving next node as histeresis
460 {
461 if (left_new_qel != 0) // possible if fqel=0
462 { // if fqel=0, all the next nodes will be deleted in total
463 // later
464 aln = aln1;
465 q = aln->el.get_qel();
466 if (left_old_qel > 0) // then getting rid of garbage
467 {
468 long l = left_old_qel;
469 if (q < l) l = q;
470 for (n = 0; n < l; n++) {
471 aln->el[n] = T();
472 }
473 }
474 }
475 while ((aln1 = aln->get_next_node()) != NULL) // deleting all next
476 // nodes
477 {
478 la.erase(aln1);
479 }
480 }
481 qel = fqel;
482 return;
483 }
484 left_old_qel -= q;
485 left_new_qel -= q;
486 aln = aln->get_next_node();
487 } while (aln != NULL);
488 qel = fqel;
489 }
490 }
491}
492
493template <class T> void BlkArr<T>::print_struct(std::ostream& file) const {
494 Ifile << "structure: qel=" << qel << " size_of_element=" << size_of_element
495 << "\n";
496 indn.n += 2;
497 long total_q = 0;
498 long n = 0;
500 if (aln != NULL) {
501 do {
502 Ifile << "n=" << n << " qel=" << aln->el.get_qel() << '\n';
503 total_q += aln->el.get_qel();
504 aln = aln->get_next_node();
505 } while (aln != NULL);
506 }
507 Ifile << "total_q=" << total_q << '\n';
508 Ifile << "end of structure.\n";
509 indn.n -= 2;
510}
511
512template <class T>
513 std::ostream& operator<<(std::ostream& file, const BlkArr<T>& f) {
514 //mfunnamep("template<class T> std::ostream& operator<<(std::ostream& file,
515 //const BlkArr<T>& f)");
516 Ifile << "BlkArr<T>: qel=" << f.get_qel() << '\n';
517 f.print_struct(file);
518 long n;
519 indn.n += 2;
520 for (n = 0; n < f.get_qel(); n++) {
521 Ifile << "n=" << n << " el[n]=" << noindent << f[n] << yesindent << '\n';
522 }
523 file << yesindent;
524 indn.n -= 2;
525 return file;
526}
527
528template <class T>
529void print_BlkArr(std::ostream& file, const DynLinArr<T>& f, int l) {
530 //mfunnamep("template<class T> void print_BlkArr(std::ostream& file, const
531 //BlkArr<T>& f, int l)");
532 Ifile << "BlkArr<T>: qel=" << f.get_qel() << '\n';
533 f.print_struct(file);
534 long n;
535 indn.n += 2;
536 for (n = 0; n < f.get_qel(); n++) {
537 Ifile << "n=" << n << " el[n]=" << noindent;
538 f[n].print(file, l);
539 }
540 file << yesindent;
541 indn.n -= 2;
542}
543
544template <class T> int operator==(const BlkArr<T>& f1, const BlkArr<T>& f2) {
545 if (f1.get_qel() != f2.get_qel()) return 0;
546 long q = f1.get_qel();
547 long n;
548 for (n = 0; n < q; n++) {
549 if (!(f1[n] == f2[n])) return 0;
550 }
551 return 1;
552}
553
554template <class T, class P>
555int apeq_mant(const BlkArr<T>& f1, const BlkArr<T>& f2, P prec) {
556 if (f1.get_qel() != f2.get_qel()) return 0;
557 long q = f1.get_qel();
558 long n;
559 for (n = 0; n < q; n++) {
560 if (!apeq_mant(f1[n], f2[n], prec)) return 0;
561 }
562 return 1;
563}
564
565template <class T> int operator!=(const BlkArr<T>& f1, const BlkArr<T>& f2) {
566 if (f1 == f2)
567 return 0;
568 else
569 return 1;
570}
571
572template <class T>
573DynLinArr<T> convert(const BlkArr<T>& f) // may be useful if one
574 // needs single chunk
575 {
576 long q = f.get_qel();
577 DynLinArr<T> temp(q);
578 long n;
579 for (n = 0; n < q; n++) {
580 temp[n] = f[n];
581 }
582 return DynLinArr<T>(temp, steal);
583
584}
585#endif
Pilfer
Definition: AbsPtr.h:512
@ steal
Definition: AbsPtr.h:513
#define PILF_MUTABLE
Definition: AbsPtr.h:143
#define PILF_CONST
Definition: AbsPtr.h:142
int operator==(const BlkArr< T > &f1, const BlkArr< T > &f2)
Definition: BlkArr.h:544
DynLinArr< T > convert(const BlkArr< T > &f)
Definition: BlkArr.h:573
int apeq_mant(const BlkArr< T > &f1, const BlkArr< T > &f2, P prec)
Definition: BlkArr.h:555
int operator!=(const BlkArr< T > &f1, const BlkArr< T > &f2)
Definition: BlkArr.h:565
const long max_size_of_extra_increment
Definition: BlkArr.h:76
void print_BlkArr(std::ostream &file, const DynLinArr< T > &f, int l)
Definition: BlkArr.h:529
std::ostream & operator<<(std::ostream &file, const BlkArr< T > &f)
Definition: BlkArr.h:513
#define spexit(stream)
Definition: FunNameStack.h:536
#define macro_alloc
Definition: ReplaceAlloc.h:10
AbsListNode< T > * get_next_node(void) const
Definition: AbsList.h:98
AbsListNode< T > * insert_after(AbsListNode< T > *an, const T &fel)
Definition: AbsList.h:487
void erase(AbsListNode< T > *an)
Definition: AbsList.h:547
AbsListNode< T > * get_last_node(void) const
Definition: AbsList.h:174
void clear(void)
Definition: AbsList.h:227
void pilfer(PILF_CONST AbsList< T > &al)
Definition: AbsList.h:664
AbsListNode< T > * get_first_node(void) const
Definition: AbsList.h:173
Definition: BlkArr.h:80
const T & operator[](long n) const
Definition: BlkArr.h:280
void decrement(void)
Definition: BlkArr.h:201
void print_struct(std::ostream &file) const
Definition: BlkArr.h:493
void clear(void)
Definition: BlkArr.h:238
macro_copy_total(BlkArr)
T & last_el(void)
Definition: BlkArr.h:304
BlkArr(void)
Definition: BlkArr.h:86
void increment(void)
Definition: BlkArr.h:197
BlkArr< T > & operator=(const BlkArr< T > &f)
Definition: BlkArr.h:113
BlkArr(long fqel, const T *ar, ArgInterp_Arr t)
Definition: BlkArr.h:95
BlkArr & assignAll(const T &f)
Definition: BlkArr.h:170
BlkArr(long fqel)
Definition: BlkArr.h:87
void pilfer(PILF_CONST BlkArr< T > &f)
Definition: BlkArr.h:145
BlkArr(long fqel, const T &val)
Definition: BlkArr.h:91
virtual ~BlkArr(void)
Definition: BlkArr.h:245
T & operator[](long n)
Definition: BlkArr.h:256
void allocate_block(long fqel)
Definition: BlkArr.h:231
void put_qel(long fqel)
Definition: BlkArr.h:354
void append(const T &val)
Definition: BlkArr.h:205
const T & last_el(void) const
Definition: BlkArr.h:329
BlkArr(const BlkArr< T > &f)
Definition: BlkArr.h:125
long get_qel(void) const
Definition: BlkArr.h:181
BlkArr(PILF_CONST BlkArr< T > &f, Pilfer)
Definition: BlkArr.h:137
long get_qel(void) const
Definition: AbsArr.h:420
indentation indn
Definition: prstream.cpp:13
std::ostream & yesindent(std::ostream &f)
Definition: prstream.cpp:19
std::ostream & noindent(std::ostream &f)
Definition: prstream.cpp:15
#define mcout
Definition: prstream.h:133
#define Ifile
Definition: prstream.h:207
#define mcerr
Definition: prstream.h:135