OpenADFortTk (including Open64 and OpenAnalysis references)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
cmplr_segmented_array.h
Go to the documentation of this file.
1 /*
2 
3  Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved.
4 
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of version 2 of the GNU General Public License as
7  published by the Free Software Foundation.
8 
9  This program is distributed in the hope that it would be useful, but
10  WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13  Further, this software is distributed without any warranty that it is
14  free of the rightful claim of any third person regarding infringement
15  or the like. Any license provided herein, whether implied or
16  otherwise, applies only to this software file. Patent licenses, if
17  any, provided herein do not apply to combinations of this program with
18  other software, or any other product whatsoever.
19 
20  You should have received a copy of the GNU General Public License along
21  with this program; if not, write the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 
24  Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky,
25  Mountain View, CA 94043, or:
26 
27  http://www.sgi.com
28 
29  For further information regarding this notice, see:
30 
31  http://oss.sgi.com/projects/GenInfo/NoticeExplan
32 
33 */
34 
35 
36 /* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */
37 
38 #ifndef cmplr_segmented_array_INCLUDED
39 #define cmplr_segmented_array_INCLUDED
40 
41 #ifndef __SGI_STL_ALGO_H
42 
43 #if defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
44 #undef short // get around bogus type defs.
45 #undef int
46 #undef long
47 #endif // defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
48 
49 #include <algorithm>
50 #include <vector>
51 
52 using std::find;
53 using std::transform;
54 using std::sort;
55 using std::stable_sort;
56 using std::rotate;
57 using std::reverse;
58 using std::set_union;
59 using std::set_intersection;
60 using std::set_difference;
61 using std::min;
62 using std::pair;
63 using std::vector;
64 
65 #endif // __SGI_STL_ALGO_H
66 
67 #ifndef __SGI_STL_VECTOR_H
68 
69 #if defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
70 #undef short // get around bogus type defs.
71 #undef int
72 #undef long
73 #endif // defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
74 
75 //# include <vector>
76 //using std::vector;
77 
78 #endif // __SGI_STL_VECTOR_H
79 
80 #ifndef __SGI_STL_SLIST_H
81 
82 #if defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
83 #undef short // get around bogus type defs.
84 #undef int
85 #undef long
86 #endif // defined(defs_INCLUDED) && !defined(USE_STANDARD_TYPES)
87 
88 
89 #include <list>
90 using std::list;
91 
92 #endif // __SGI_STL_LIST_H
93 
94 
95 #ifndef ERRORS_INCLUDED
96 #include "errors.h"
97 #endif // ERRORS_INCLUDED
98 
99 #ifndef mempool_INCLUDED
100 #include "mempool.h"
101 #endif // mempool_INCLUDED
102 
103 #ifndef segmented_array_INCLUDED
104 #include "segmented_array.h" // for SEGMENTED_ARRAY_ITERATOR
105 #endif // segmented_array_INCLUDED
106 
107 #ifndef mempool_allocator_INCLUDED
108 #include "mempool_allocator.h"
109 #endif
110 
111 // ======================================================================
112 // ======================================================================
113 // A RELATED_SEGMENTED_ARRAY is a segmented array that can enter into
114 // a particular kind of relationship with other
115 // RELATED_SEGMENTED_ARRAYs. The particular relationship is this: When
116 // one of the arrays (called the primary one) in the pair grows or
117 // shrinks, the other one (called the secondary, or child, or kid) grows
118 // automatically. The secondary array may be primary in relationships
119 // of its own, in which case its child(ren) is (are) resized
120 // automatically, etc.
121 //
122 // From the time that the relationship is established between two
123 // segmented arrays until the relationship is dissolved, we maintain
124 // the invariant that an index is a valid subscript for one of the
125 // arrays if and only if it is a valid subscript for the other one.
126 //
127 // This invariant is maintained only "top-down"; if a
128 // RELATED_SEGMENTED_ARRAY is a registered kid of another
129 // RELATED_SEGMENTED_ARRAY, the behavior is undefined if the kid is
130 // resized by some operation other than the automatic resizing that
131 // takes place when its parent gets resized.
132 //
133 // To accomplish all this in a clean way, we apparently need some
134 // dirty C++: inheritance!
135 //
136 // RELATED_SEGMENTED_ARRAYs are used in the compiler when we want to
137 // maintain phase-specific tables alongside long-lived tables (usually
138 // as part of the morass of tables we call the "symbol table"). For
139 // example, the PREG_TAB lives throughout the compiler (front end
140 // through code generator), and contains no representation of home
141 // locations. In the back end, when we assign a home location to a
142 // PREG, we store the home location information in a secondary table
143 // of type BE_PREG_TAB. When we begin compiling a PU in the back end,
144 // we register the BE_PREG_TAB with the PREG_TAB, establishing that
145 // the PREG_TAB is primary and the BE_PREG_TAB is secondary in that
146 // relationship. Then we are assured that the BE_PREG_TAB can be
147 // indexed by exactly those indices that we use for the PREG_TAB. At
148 // the beginning of the back end's work on each PU, the BE_PREG_TAB is
149 // registered as a kid of the PREG_TAB using the routine
150 // growing_table::Register; this registration is the beginning of the
151 // relationship during which the secondary table (BE_PREG_TAB) is kept
152 // in sync with all grow/shrink operations that affect the primary
153 // table (PREG_TAB). The relationship ends when
154 // growing_table::Un_register is called to dissociate the pair.
155 //
156 // A more complicated usage example arises when we want to maintain
157 // some table in parallel with the multi-layered Symbol_Table
158 // structure. For an example of how that's done in the F90 front end,
159 // see mongoose/crayf90/sgi/cwh_stab.i, which declares an auxilliary
160 // table indexed by ST_IDX and called AUXST_TABLE.
161 //
162 // Note that the class T used in RELATED_SEGMENTED_ARRAY should have a constructor
163 // if it needs any initilization (i.e, be careful about RELATED_SEGMENTED_ARRAY<int> or
164 // RELATED_SEGMENTED_ARRAY<FOO *>).
165 //
166 // ======================================================================
167 // ======================================================================
168 
169 // TODO: Add assertions.
170 // Make block-growth more efficient.
171 
173 protected:
174  UINT size; // total number of elements present
175 
176 private:
177 
178  typedef std::list<growing_table *> kids_type;
179 
181 
182  virtual void Construct_new_entry(void) = 0;
183  virtual void Construct_new_entry(UINT n) = 0;
184  virtual void Delete_last(void) = 0;
185  virtual void Delete_last(UINT n) = 0;
186 
187 protected:
188  // Here each RELATED_SEGMENTED_ARRAY member function that changes
189  // the size is represented by a member function. Note that we
190  // can represent only primitives that are independent of the
191  // segmented array's base type, since this base class isn't (and
192  // can't be) a template.
194  {
195  for (kids_type::iterator kid = kids.begin();
196  kid != kids.end();
197  ++kid) {
198  (*kid)->Delete_last();
199  }
200  }
201 
203  {
204  for (kids_type::iterator kid = kids.begin();
205  kid != kids.end();
206  ++kid) {
207  (*kid)->Delete_last(n);
208  }
209  }
210 
212  {
213  for (kids_type::iterator kid = kids.begin();
214  kid != kids.end();
215  ++kid) {
216  (*kid)->Construct_new_entry();
217  }
218  }
219 
221  {
222  for (kids_type::iterator kid = kids.begin();
223  kid != kids.end();
224  ++kid) {
225  (*kid)->Construct_new_entry(n);
226  }
227  }
228 
229 public:
230  growing_table() : size(0) { }
231  virtual ~growing_table() { }
232 
233  // Here we have a member function to register a new kid with this
234  // growing_table.
236  {
237  // Make sure the new kid is of the right size:
238  FmtAssert(kid.size <= size,
239  ("growing_table::Register: child must not be larger "
240  "than parent"));
241  // TODO: Cheesy, inefficient method for now.
242  while (kid.size < size) {
243  kid.Construct_new_entry();
244  }
245 
246  // Put the new kid into the list of kids:
247  kids.push_front(&kid);
248  }
249 
251  {
252  kids_type::iterator kid_ptr = std::find(kids.begin(), kids.end(), &kid);
253  if (kid_ptr != kids.end()) {
254  kids.erase(kid_ptr);
255  }
256  else {
257  Fail_FmtAssertion("RELATED_SEGMENTED_ARRAY: Cannot un-register "
258  "an unregistered kid");
259  }
260  }
261 };
262 
263 template <class T, UINT block_size = 128>
265 private:
266 
267  std::vector<std::pair<T *, BOOL>, mempool_allocator<std::pair<T *,BOOL> > > map;
268 
270  UINT max_size; // total # of elements allocated
271  INT block_base; // idx of the beginning of
272  // block (signed so we can set
273  // to -1, meaning no block allocated)
274  UINT next_block_size; // size of block to be allocated
275  T *block; // points to the last block
276 
277 private:
278 
280 
281 public:
282  typedef T base_type;
283 
284  typedef T value_type;
285  typedef value_type* pointer;
286  typedef const value_type* const_pointer;
288  typedef const value_type& const_reference;
289  typedef UINT size_type;
291 
294  typedef SEGMENTED_ARRAY_ITERATOR<const self*, T,
297 
298 private:
299  // private operations
300 
301  virtual void Construct_new_entry(void)
302  {
303  if (size == max_size) Allocate();
305  new(&block[size++ - block_base]) T(); // T() makes sure the
306  // default constructor
307  // is called. T without
308  // parens would not
309  // ensure this.
310  }
311 
312  virtual void Construct_new_entry(UINT n)
313  {
314  // Cheesy implementation for now to get things working without
315  // the risk of having to think.
316  for (; n > 0; n--) {
318  }
319  }
320 
322  UINT mask = block_size - 1;
323  return (s + mask) & ~mask;
324  }
325 
326  void Update_Map (T *marker, UINT new_size, BOOL own_memory);
327 
328  void Pop_Map ();
329 
330  // allocate a block, assume the array is completely filled
331  void Allocate ();
332 
333  T& New_entry () {
334 
335  if (size == max_size) Allocate ();
337  return block[size++ - block_base];
338  }
339 
340  // copy n elements to current buffer, assume no overflow
341  void Copy (const T* x, UINT n) {
342  std::copy(x, x + n, block + (size - block_base));
343  size += n;
345  }
346 
347  // block_idx is an index into the map. This function returns
348  // the first map index that points to a different block.
349  UINT next_block_idx(UINT block_idx) const {
350  for ( ; block_idx + 1 < map.size() &&
351  map[block_idx].first + block_size == map[block_idx + 1].first;
352  ++block_idx)
353  {}
354  return block_idx + 1;
355  }
356 
357 public:
358 
360  size = max_size = next_block_size = 0;
361  block_base = -1;
362  block = 0;
363  }
364 
366  // Free memory from blocks. Map memory gets freed when the map
367  // vector is destructed.
368  typedef typename vector<pair<T *, BOOL>, mempool_allocator<pair<T *, BOOL> > >::iterator TempIteratorType;
369  for ( TempIteratorType entry = map.begin(); entry != map.end(); ++entry ) {
370  // entry->second <==> this map entry owns the block's memory.
371  if (entry->second) {
372  MEM_POOL_FREE(pool, entry->first);
373  }
374  }
375  }
376 
377  UINT Block_size () const { return block_size; }
378 
379  UINT Size () const { return growing_table::size; }
380 
381  T& Entry (UINT idx) {
382  Is_True (idx < size, ("Array subscript out of bound"));
383  return map[idx / block_size].first[idx % block_size];
384  }
385 
386  const T& Entry (UINT idx) const {
387  Is_True (idx < size, ("Array subscript out of bound"));
388  return map[idx / block_size].first[idx % block_size];
389  }
390 
391 
392  T& operator[] (UINT idx) { return Entry(idx); }
393  const T& operator[] (UINT idx) const { return Entry(idx); }
394 
396  return iterator (this, map[0].first, Block_end (0), 0);
397  }
398 
400  return iterator (this, block + (size - block_base),
401  block + (max_size - block_base), size);
402  }
403 
405  return const_iterator (this, map[0].first, Block_end (0), 0);
406  }
407 
408  const_iterator end () const {
409  return const_iterator (this, block + (size - block_base),
410  block + (max_size - block_base), size);
411  }
412 
413  T& New_entry (UINT& idx) { idx = size; return New_entry (); }
414 
415  UINT Insert (const T& x);
416 
417  virtual void Delete_last () {
418  size--;
420  if (size == (UINT)block_base)
421  Pop_Map ();
422  }
423 
424  virtual void Delete_last (UINT n);
425 
426  // insert multiple elements, always copy to new buffer.
427  UINT Insert (const T* x, UINT n_elemt);
428 
429  // similar to insert, except reuse the given buffer if possible
430  UINT Transfer (T* x, UINT n_elemt);
431 
432  // Reserve extra storage. Actual allocation will be done when the
433  // already allocated storage is filled.
434  void Reserve (UINT n_elemt) {
435  if (max_size - size + next_block_size < n_elemt)
436  next_block_size = n_elemt - (max_size - size);
437  }
438 
439  // return the number of element till the end of the block
441  UINT block_idx = idx / block_size;
442  return min(next_block_idx(block_idx) * block_size, size) - idx;
443  }
444 
445  UINT Block_index (UINT idx) const { return idx / block_size; }
446 
447  // A valid block index n is in the range 0 <= n < Block_index_end().
448  UINT Block_index_end () const { return map.size(); }
449 
450  T* Block_begin (UINT block_idx) { return map[block_idx].first; }
451  const T* Block_begin (UINT block_idx) const { return map[block_idx].first; }
452 
453  T* Block_end(UINT block_idx) {
454  return Block_begin(block_idx) +
455  (next_block_idx(block_idx) - block_idx) * block_size;
456  }
457 
458  const T* Block_end(UINT block_idx) const {
459  return Block_begin(block_idx) +
460  (next_block_idx(block_idx) - block_idx) * block_size;
461  }
462 
463  void Clear(void);
464 }; // RELATED_SEGMENTED_ARRAY
465 
466 template <class T, UINT block_size>
467 inline void
469  UINT new_size,
470  BOOL own_memory)
471 {
472  do {
473 
474  map.push_back(std::pair<T*, BOOL>(marker, own_memory));
475  new_size -= block_size;
476  marker += block_size;
477  } while (new_size);
478 } // RELATED_SEGMENTED_ARRAY<T,block_size>::Update_Map
479 
480 
481 // deallocate a block and re-adjust the map and other variables
482 template <class T, UINT block_size>
483 void
485 {
486  next_block_size += max_size - block_base;
487  MEM_POOL_FREE (pool, block);
488 
489  T *last_map_entry;
490  do {
491  last_map_entry = (map.end() - 1)->first;
492  map.pop_back ();
493  } while (last_map_entry != block);
494 
495  max_size = size;
496  if (size > 0) {
497  Is_True(size >= block_size,
498  ("RELATED_SEGMENTED_ARRAY: size in limbo"));
499  block_base = size - block_size;
500  UINT idx = block_base / block_size;
501  block = map[idx].first;
502  while (idx > 0 && map[idx - 1].first + block_size == block) {
503  block = map[--idx].first;
504  block_base -= block_size;
505  }
506  }
507  else {
508  Is_True(map.begin() == map.end(),
509  ("RELATED_SEGMENTED_ARRAY::Pop_Map: Map should be empty"));
510  block_base = -1;
511  block = NULL;
512  }
513 } // RELATED_SEGMENTED_ARRAY<T,block_size>::Pop_Map
514 
515 
516 template <class T, UINT block_size>
517 void
519 {
520  Is_True (size == max_size, ("Invalid internal state in segmented array"));
521 
522  UINT new_size;
523 
524  if (next_block_size == 0)
525  new_size = block_size;
526  else {
527  new_size = Round_up (next_block_size);
528  next_block_size = 0;
529  }
530 
531  block = (T *) MEM_POOL_Alloc (pool, new_size * sizeof(T));
532  max_size += new_size;
533  block_base = size;
534 
535  Update_Map (block, new_size, TRUE);
536 
537 } // RELATED_SEGMENTED_ARRAY::Allocate
538 
539 
540 template <class T, UINT block_size>
541 void
543 {
544  while (n >= size - block_base) {
545  n -= size - block_base;
546  size = block_base;
547  Pop_Map ();
548  }
549  size -= n;
550  Decrease_kids_size(n);
551 } // Delete_last
552 
553 
554 template <class T, UINT block_size>
555 inline UINT
557 {
558  UINT idx = size;
559  T &entry = New_entry ();
560 
561  entry = x;
562  return idx;
563 } // RELATED_SEGMENTED_ARRAY::Insert
564 
565 
566 template <class T, UINT block_size>
567 UINT
569 {
570  UINT result = size;
571  if (size + n_elemt <= max_size) {
572  Copy (x, n_elemt);
573  return result;
574  }
575 
576  UINT space_left = max_size - size;
577  Copy (x, space_left);
578  n_elemt -= space_left;
579 
580  Reserve (n_elemt);
581  Allocate ();
582  Copy (x + space_left, n_elemt);
583 
584  return result;
585 } // RELATED_SEGMENTED_ARRAY::Insert
586 
587 
588 template <class T, UINT block_size>
589 UINT
591 {
592  UINT result = size;
593 
594  if (size + n_elemt <= max_size) {
595  Copy (x, n_elemt);
596  return result;
597  }
598 
599  UINT space_left = max_size - size;
600  if (space_left > 0) {
601  Copy (x, space_left);
602  n_elemt -= space_left;
603  x += space_left;
604  }
605 
606  if (n_elemt >= block_size) {
607  UINT reused_size = n_elemt & ~(block_size - 1);
608  block = x;
609  Update_Map (block, reused_size, FALSE);
610  block_base = size;
611  size += reused_size;
612  max_size += reused_size;
613  n_elemt -= reused_size;
614  x += reused_size;
615  if (next_block_size > reused_size)
616  next_block_size -= reused_size;
617  else
618  next_block_size = 0;
619  }
620 
621  if (n_elemt > 0) {
622  Allocate ();
623  Copy (x, n_elemt);
624  }
625 
626  return result;
627 } // RELATED_SEGMENTED_ARRAY::Transfer
628 
629 // Release all resources and return the RELATED_SEGMENTED_ARRAY to a
630 // pristine state.
631 template <class T, UINT block_size>
632 void
634 {
635  if (growing_table::size > 0) {
636  Delete_last(growing_table::size);
637  }
638  Is_True(map.begin() == map.end(),
639  ("RELATED_SEGMENTED_ARRAY::Clear: Map should be empty"));
640 }
641 
642 template <class T, UINT block_size, class OP>
643 inline void
645  const OP &op,
646  UINT32 first = 0)
647 {
648  UINT last = array.Size ();
649 
650  while (first < last) {
651  T *block = &array[first];
652  UINT size = array.Get_block_size (first);
653  for (UINT j = 0; j < size; ++j, ++block)
654  op (first + j, block);
655  first += size;
656  }
657 }
658 
659 // The following function is ifdefed out because, until we have
660 // partial ordering of function templates, the compiler will flag it
661 // as ambiguous.
662 #if 0
663 
664 template <class T, UINT block_size, class OP>
665 inline void
667  const OP &op,
668  UINT32 first = 0)
669 {
670  UINT last = array.Size ();
671 
672  while (first < last) {
673  const T *block = &array[first];
674  UINT size = array.Get_block_size (first);
675  for (UINT j = 0; j < size; ++j, ++block)
676  op (first + j, block);
677  first += size;
678  }
679 }
680 
681 #endif
682 
683 template <class T, UINT block_size, class OP>
684 inline void
686 {
687  UINT max_size = array.Size ();
688  UINT i = 0;
689 
690  while (i < max_size) {
691  T *block = &array[i];
692  UINT size = array.Get_block_size (i);
693  op (i, block, size);
694  i += size;
695  }
696 }
697 
698 
699 #define NOT_FOUND ((UINT) -1)
700 
701 template <class T, UINT block_size, class PREDICATE>
702 inline UINT
704  const PREDICATE& pred, UINT i = 0)
705 {
706  UINT max_size = array.Size ();
707 
708  while (i < max_size) {
709  const T *block = &array[i];
710  UINT size = array.Get_block_size (i);
711  for (UINT j = 0; j < size; ++j, ++block)
712  if (pred (i+j, block))
713  return i + j;
714  i += size;
715  }
716 
717  return (UINT) NOT_FOUND;
718 }
719 
720 
721 // copy the content of one segmented array to another, optionally specified
722 // the range [first_idx, last_idx) to be copied.
723 // returns the number of entries copied.
724 template <class T, UINT block_size>
725 UINT32
728  UINT32 first_idx = 0, UINT32 last_idx = (UINT32) -1)
729 {
730  if (last_idx > from_array.Size ())
731  last_idx = from_array.Size ();
732 
733  Is_True (last_idx >= first_idx, ("Invalid copy range"));
734 
735  UINT32 entries = last_idx - first_idx;
736 
737  to_array.Reserve (entries);
738 
739  while (first_idx < last_idx) {
740  const T* block = &from_array[first_idx];
741  UINT32 size = from_array.Get_block_size (first_idx);
742  if (size > last_idx - first_idx)
743  size = last_idx - first_idx;
744 
745  to_array.Insert (block, size);
746  first_idx += size;
747  }
748 
749  return entries;
750 } // Copy_array_range
751 
752 #endif // cmplr_segmented_array_INCLUDED