source: src/Common/utility.h@ fbdfcd8

ADT ast-experimental
Last change on this file since fbdfcd8 was 4b60b28, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Moved parser utility from common utility file to the parserutility file.

  • Property mode set to 100644
File size: 17.9 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// utility.h --
8//
9// Author : Richard C. Bilson
10// Created On : Mon May 18 07:44:20 2015
11// Last Modified By : Andrew Beach
12// Last Modified On : Thr Feb 16 12:35:00 2023
13// Update Count : 52
14//
15
16#pragma once
17
18#include <cassert>
19#include <cctype>
20#include <algorithm>
21#include <functional>
22#include <iostream>
23#include <iterator>
24#include <list>
25#include <memory>
26#include <sstream>
27#include <string>
28#include <type_traits>
29#include <utility>
30#include <vector>
31#include <cstring> // memcmp
32
33#include "Common/Indenter.h"
34
35class Expression;
36
37/// bring std::move into global scope
38using std::move;
39
40/// partner to move that copies any copyable type
41template<typename T>
42T copy( const T & x ) { return x; }
43
44template< typename T >
45static inline T * maybeClone( const T *orig ) {
46 if ( orig ) {
47 return orig->clone();
48 } else {
49 return 0;
50 } // if
51}
52
53template< typename Input_iterator >
54void printEnums( Input_iterator begin, Input_iterator end, const char * const *name_array, std::ostream &os ) {
55 for ( Input_iterator i = begin; i != end; ++i ) {
56 os << name_array[ *i ] << ' ';
57 } // for
58}
59
60template< typename Container >
61void deleteAll( const Container &container ) {
62 for ( const auto &i : container ) {
63 delete i;
64 } // for
65}
66
67template< typename Container >
68void printAll( const Container &container, std::ostream &os, Indenter indent = {} ) {
69 for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
70 if ( *i ) {
71 os << indent;
72 (*i)->print( os, indent );
73 // need an endl after each element because it's not easy to know when each individual item should end
74 os << std::endl;
75 } // if
76 } // for
77}
78
79template< typename SrcContainer, typename DestContainer >
80void cloneAll( const SrcContainer &src, DestContainer &dest ) {
81 typename SrcContainer::const_iterator in = src.begin();
82 std::back_insert_iterator< DestContainer > out( dest );
83 while ( in != src.end() ) {
84 *out++ = (*in++)->clone();
85 } // while
86}
87
88template< typename SrcContainer, typename DestContainer, typename Predicate >
89void cloneAll_if( const SrcContainer &src, DestContainer &dest, Predicate pred ) {
90 std::back_insert_iterator< DestContainer > out( dest );
91 for ( auto x : src ) {
92 if ( pred(x) ) {
93 *out++ = x->clone();
94 }
95 } // while
96}
97
98template< typename Container >
99void assertAll( const Container &container ) {
100 int count = 0;
101 for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
102 if ( !(*i) ) {
103 std::cerr << count << " is null" << std::endl;
104 } // if
105 } // for
106}
107
108template < typename T >
109std::list<T> tail( std::list<T> l ) {
110 if ( ! l.empty() ) {
111 std::list<T> ret(++(l.begin()), l.end());
112 return ret;
113 } // if
114}
115
116template < typename T >
117std::list<T> flatten( std::list < std::list<T> > l) {
118 typedef std::list <T> Ts;
119
120 Ts ret;
121
122 switch ( l.size() ) {
123 case 0:
124 return ret;
125 case 1:
126 return l.front();
127 default:
128 ret = flatten(tail(l));
129 ret.insert(ret.begin(), l.front().begin(), l.front().end());
130 return ret;
131 } // switch
132}
133
134/// Splice src onto the end of dst, clearing src
135template< typename T >
136void splice( std::vector< T > & dst, std::vector< T > & src ) {
137 dst.reserve( dst.size() + src.size() );
138 for ( T & x : src ) { dst.emplace_back( std::move( x ) ); }
139 src.clear();
140}
141
142/// Splice src onto the begining of dst, clearing src
143template< typename T >
144void spliceBegin( std::vector< T > & dst, std::vector< T > & src ) {
145 splice( src, dst );
146 dst.swap( src );
147}
148
149template < typename T >
150void toString_single( std::ostream & os, const T & value ) {
151 os << value;
152}
153
154template < typename T, typename... Params >
155void toString_single( std::ostream & os, const T & value, const Params & ... params ) {
156 os << value;
157 toString_single( os, params ... );
158}
159
160template < typename ... Params >
161std::string toString( const Params & ... params ) {
162 std::ostringstream os;
163 toString_single( os, params... );
164 return os.str();
165}
166
167#define toCString( ... ) toString( __VA_ARGS__ ).c_str()
168
169// replace element of list with all elements of another list
170template< typename T >
171void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) {
172 typename std::list< T >::iterator next = pos; advance( next, 1 );
173
174 //if ( next != org.end() ) {
175 org.erase( pos );
176 org.splice( next, with );
177 //}
178
179 return;
180}
181
182// replace range of a list with a single element
183template< typename T >
184void replace( std::list< T > &org, typename std::list< T >::iterator begin, typename std::list< T >::iterator end, const T & with ) {
185 org.insert( begin, with );
186 org.erase( begin, end );
187}
188
189template< typename... Args >
190auto filter(Args&&... args) -> decltype(std::copy_if(std::forward<Args>(args)...)) {
191 return std::copy_if(std::forward<Args>(args)...);
192}
193
194template <typename E, typename UnaryPredicate, template< typename, typename...> class Container, typename... Args >
195void filter( Container< E *, Args... > & container, UnaryPredicate pred, bool doDelete ) {
196 auto i = begin( container );
197 while ( i != end( container ) ) {
198 auto it = next( i );
199 if ( pred( *i ) ) {
200 if ( doDelete ) {
201 delete *i;
202 } // if
203 container.erase( i );
204 } // if
205 i = it;
206 } // while
207}
208
209template<typename Container, typename Pred>
210void erase_if( Container & cont, Pred && pred ) {
211 auto keep_end = std::remove_if( cont.begin(), cont.end(), pred );
212 cont.erase( keep_end, cont.end() );
213}
214
215template< typename... Args >
216auto zip(Args&&... args) -> decltype(zipWith(std::forward<Args>(args)..., std::make_pair)) {
217 return zipWith(std::forward<Args>(args)..., std::make_pair);
218}
219
220template< class InputIterator1, class InputIterator2, class OutputIterator, class BinFunction >
221void zipWith( InputIterator1 b1, InputIterator1 e1, InputIterator2 b2, InputIterator2 e2, OutputIterator out, BinFunction func ) {
222 while ( b1 != e1 && b2 != e2 )
223 *out++ = func(*b1++, *b2++);
224}
225
226// it's nice to actually be able to increment iterators by an arbitrary amount
227template< class InputIt, class Distance >
228InputIt operator+( InputIt it, Distance n ) {
229 advance(it, n);
230 return it;
231}
232
233template< typename T >
234void warn_single( const T & arg ) {
235 std::cerr << arg << std::endl;
236}
237
238template< typename T, typename... Params >
239void warn_single(const T & arg, const Params & ... params ) {
240 std::cerr << arg;
241 warn_single( params... );
242}
243
244template< typename... Params >
245void warn( const Params & ... params ) {
246 std::cerr << "Warning: ";
247 warn_single( params... );
248}
249
250// determines if pref is a prefix of str
251static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
252 if ( pref.size() > str.size() ) return false;
253 return 0 == memcmp( str.c_str() + start, pref.c_str(), pref.size() );
254 // return prefix == full.substr(0, prefix.size()); // for future, requires c++17
255}
256
257// -----------------------------------------------------------------------------
258// Ref Counted Singleton class
259// Objects that inherit from this class will have at most one reference to it
260// but if all references die, the object will be deleted.
261
262template< typename ThisType >
263class RefCountSingleton {
264 public:
265 static std::shared_ptr<ThisType> get() {
266 if( global_instance.expired() ) {
267 std::shared_ptr<ThisType> new_instance = std::make_shared<ThisType>();
268 global_instance = new_instance;
269 return std::move(new_instance);
270 }
271 return global_instance.lock();
272 }
273 private:
274 static std::weak_ptr<ThisType> global_instance;
275};
276
277template< typename ThisType >
278std::weak_ptr<ThisType> RefCountSingleton<ThisType>::global_instance;
279
280// -----------------------------------------------------------------------------
281// RAII object to regulate "save and restore" behaviour, e.g.
282// void Foo::bar() {
283// ValueGuard<int> guard(var); // var is a member of type Foo
284// var = ...;
285// } // var's original value is restored
286template< typename T >
287struct ValueGuard {
288 T old;
289 T& ref;
290
291 ValueGuard(T& inRef) : old(inRef), ref(inRef) {}
292 ~ValueGuard() { ref = old; }
293};
294
295template< typename T >
296struct ValueGuardPtr {
297 T old;
298 T* ref;
299
300 ValueGuardPtr(T * inRef) : old( inRef ? *inRef : T() ), ref(inRef) {}
301 ValueGuardPtr(const ValueGuardPtr& other) = delete;
302 ValueGuardPtr(ValueGuardPtr&& other) : old(other.old), ref(other.ref) { other.ref = nullptr; }
303 ~ValueGuardPtr() { if( ref ) *ref = old; }
304};
305
306template< typename aT >
307struct FuncGuard {
308 aT m_after;
309
310 template< typename bT >
311 FuncGuard( bT before, aT after ) : m_after( after ) {
312 before();
313 }
314
315 ~FuncGuard() {
316 m_after();
317 }
318};
319
320template< typename bT, typename aT >
321FuncGuard<aT> makeFuncGuard( bT && before, aT && after ) {
322 return FuncGuard<aT>( std::forward<bT>(before), std::forward<aT>(after) );
323}
324
325template< typename T >
326struct ValueGuardPtr< std::list< T > > {
327 std::list< T > old;
328 std::list< T >* ref;
329
330 ValueGuardPtr( std::list< T > * inRef) : old(), ref(inRef) {
331 if( ref ) { swap( *ref, old ); }
332 }
333 ~ValueGuardPtr() { if( ref ) { swap( *ref, old ); } }
334};
335
336// -----------------------------------------------------------------------------
337// Helper struct and function to support
338// for ( val : reverseIterate( container ) ) {}
339// syntax to have a for each that iterates backwards
340
341template< typename T >
342struct reverse_iterate_t {
343 T& ref;
344
345 reverse_iterate_t( T & ref ) : ref(ref) {}
346
347 // this does NOT work on const T!!!
348 // typedef typename T::reverse_iterator iterator;
349 auto begin() { return ref.rbegin(); }
350 auto end() { return ref.rend(); }
351};
352
353template< typename T >
354reverse_iterate_t< T > reverseIterate( T & ref ) {
355 return reverse_iterate_t< T >( ref );
356}
357
358template< typename T >
359struct enumerate_t {
360 template<typename val_t>
361 struct value_t {
362 val_t & val;
363 size_t idx;
364 };
365
366 template< typename iter_t, typename val_t >
367 struct iterator_t {
368 iter_t it;
369 size_t idx;
370
371 iterator_t( iter_t _it, size_t _idx ) : it(_it), idx(_idx) {}
372
373 value_t<val_t> operator*() const { return value_t<val_t>{ *it, idx }; }
374
375 bool operator==(const iterator_t & o) const { return o.it == it; }
376 bool operator!=(const iterator_t & o) const { return o.it != it; }
377
378 iterator_t & operator++() {
379 it++;
380 idx++;
381 return *this;
382 }
383
384 using difference_type = typename std::iterator_traits< iter_t >::difference_type;
385 using value_type = value_t<val_t>;
386 using pointer = value_t<val_t> *;
387 using reference = value_t<val_t> &;
388 using iterator_category = std::forward_iterator_tag;
389 };
390
391 T & ref;
392
393 using iterator = iterator_t< typename T::iterator, typename T::value_type >;
394 using const_iterator = iterator_t< typename T::const_iterator, const typename T::value_type >;
395
396 iterator begin() { return iterator( ref.begin(), 0 ); }
397 iterator end() { return iterator( ref.end(), ref.size() ); }
398
399 const_iterator begin() const { return const_iterator( ref.cbegin(), 0 ); }
400 const_iterator end() const { return const_iterator( ref.cend(), ref.size() ); }
401
402 const_iterator cbegin() const { return const_iterator( ref.cbegin(), 0 ); }
403 const_iterator cend() const { return const_iterator( ref.cend(), ref.size() ); }
404};
405
406template< typename T >
407enumerate_t<T> enumerate( T & ref ) {
408 return enumerate_t< T >{ ref };
409}
410
411template< typename T >
412const enumerate_t< const T > enumerate( const T & ref ) {
413 return enumerate_t< const T >{ ref };
414}
415
416template< typename OutType, typename Range, typename Functor >
417OutType map_range( const Range& range, Functor&& functor ) {
418 OutType out;
419
420 std::transform(
421 begin( range ),
422 end( range ),
423 std::back_inserter( out ),
424 std::forward< Functor >( functor )
425 );
426
427 return out;
428}
429
430// -----------------------------------------------------------------------------
431// Helper struct and function to support:
432// for ( auto val : group_iterate( container1, container2, ... ) ) { ... }
433// This iteraters through multiple containers of the same size.
434
435template<typename... Args>
436class group_iterate_t {
437 using Iterables = std::tuple<Args...>;
438 Iterables iterables;
439
440 // Getting the iterator and value types this way preserves const.
441 template<size_t I> using Iter = decltype(std::get<I>(iterables).begin());
442 template<size_t I> using Data = decltype(*std::get<I>(iterables).begin());
443 template<typename> struct base_iterator;
444
445 // This inner template puts the sequence of `0, 1, ... sizeof...(Args)-1`
446 // into a pack. These are the indexes into the tuples, so unpacking can
447 // go over each element of the tuple.
448 // The std::integer_sequence is just used to build that sequence.
449 // A library reference will probably explain it better than I can.
450 template<std::size_t... Indices>
451 struct base_iterator<std::integer_sequence<std::size_t, Indices...>> {
452 using value_type = std::tuple< Data<Indices>... >;
453 std::tuple<Iter<Indices>...> iterators;
454
455 base_iterator( Iter<Indices>... is ) : iterators( is... ) {}
456 base_iterator operator++() {
457 return base_iterator( ++std::get<Indices>( iterators )... );
458 }
459 bool operator!=( const base_iterator& other ) const {
460 return iterators != other.iterators;
461 }
462 value_type operator*() const {
463 return std::tie( *std::get<Indices>( iterators )... );
464 }
465
466 static base_iterator make_begin( Iterables & data ) {
467 return base_iterator( std::get<Indices>( data ).begin()... );
468 }
469 static base_iterator make_end( Iterables & data ) {
470 return base_iterator( std::get<Indices>( data ).end()... );
471 }
472 };
473
474public:
475 group_iterate_t( const Args &... args ) : iterables( args... ) {}
476
477 using iterator = base_iterator<decltype(
478 std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
479
480 iterator begin() { return iterator::make_begin( iterables ); }
481 iterator end() { return iterator::make_end( iterables ); }
482};
483
484// Helpers for the bounds checks (the non-varatic part of group_iterate):
485static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
486 assertf( size0 == size1,
487 "group iteration requires containers of the same size: <%zd, %zd>.",
488 size0, size1 );
489}
490
491static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
492 assertf( size0 == size1 && size1 == size2,
493 "group iteration requires containers of the same size: <%zd, %zd, %zd>.",
494 size0, size1, size2 );
495}
496
497/// Performs bounds check to ensure that all arguments are of the same length.
498template< typename... Args >
499group_iterate_t<Args...> group_iterate( Args &&... args ) {
500 runGroupBoundsCheck( args.size()... );
501 return group_iterate_t<Args...>( std::forward<Args>( args )... );
502}
503
504/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
505template< typename... Args >
506group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
507 return group_iterate_t<Args...>( std::forward<Args>( args )... );
508}
509
510// -----------------------------------------------------------------------------
511// Helper struct and function to support
512// for ( val : lazy_map( container1, f ) ) {}
513// syntax to have a for each that iterates a container, mapping each element by applying f
514template< typename T, typename Func >
515struct lambda_iterate_t {
516 const T & ref;
517 std::function<Func> f;
518
519 struct iterator {
520 typedef decltype(begin(ref)) Iter;
521 Iter it;
522 std::function<Func> f;
523 iterator( Iter it, std::function<Func> f ) : it(it), f(f) {}
524 iterator & operator++() {
525 ++it; return *this;
526 }
527 bool operator!=( const iterator &other ) const { return it != other.it; }
528 auto operator*() const -> decltype(f(*it)) { return f(*it); }
529 };
530
531 lambda_iterate_t( const T & ref, std::function<Func> f ) : ref(ref), f(f) {}
532
533 auto begin() const -> decltype(iterator(std::begin(ref), f)) { return iterator(std::begin(ref), f); }
534 auto end() const -> decltype(iterator(std::end(ref), f)) { return iterator(std::end(ref), f); }
535};
536
537template< typename... Args >
538lambda_iterate_t<Args...> lazy_map( const Args &... args ) {
539 return lambda_iterate_t<Args...>( args...);
540}
541
542// -----------------------------------------------------------------------------
543// O(1) polymorphic integer ilog2, using clz, which returns the number of leading 0-bits, starting at the most
544// significant bit (single instruction on x86)
545
546template<typename T>
547inline
548#if defined(__GNUC__) && __GNUC__ > 4
549constexpr
550#endif
551T ilog2(const T & t) {
552 if(std::is_integral<T>::value) {
553 const constexpr int r = sizeof(t) * __CHAR_BIT__ - 1;
554 if( sizeof(T) == sizeof(unsigned int) ) return r - __builtin_clz ( t );
555 if( sizeof(T) == sizeof(unsigned long) ) return r - __builtin_clzl ( t );
556 if( sizeof(T) == sizeof(unsigned long long) ) return r - __builtin_clzll( t );
557 }
558 assert(false);
559 return -1;
560} // ilog2
561
562// -----------------------------------------------------------------------------
563/// evaluates expr as a long long int. If second is false, expr could not be evaluated
564std::pair<long long int, bool> eval(const Expression * expr);
565
566namespace ast {
567 class Expr;
568}
569
570std::pair<long long int, bool> eval(const ast::Expr * expr);
571
572// -----------------------------------------------------------------------------
573/// Reorders the input range in-place so that the minimal-value elements according to the
574/// comparator are in front;
575/// returns the iterator after the last minimal-value element.
576template<typename Iter, typename Compare>
577Iter sort_mins( Iter begin, Iter end, Compare& lt ) {
578 if ( begin == end ) return end;
579
580 Iter min_pos = begin;
581 for ( Iter i = begin + 1; i != end; ++i ) {
582 if ( lt( *i, *min_pos ) ) {
583 // new minimum cost; swap into first position
584 min_pos = begin;
585 std::iter_swap( min_pos, i );
586 } else if ( ! lt( *min_pos, *i ) ) {
587 // duplicate minimum cost; swap into next minimum position
588 ++min_pos;
589 std::iter_swap( min_pos, i );
590 }
591 }
592 return ++min_pos;
593}
594
595template<typename Iter, typename Compare>
596inline Iter sort_mins( Iter begin, Iter end, Compare&& lt ) {
597 return sort_mins( begin, end, lt );
598}
599
600/// sort_mins defaulted to use std::less
601template<typename Iter>
602inline Iter sort_mins( Iter begin, Iter end ) {
603 return sort_mins( begin, end, std::less<typename std::iterator_traits<Iter>::value_type>{} );
604}
605
606// Local Variables: //
607// tab-width: 4 //
608// mode: c++ //
609// compile-command: "make install" //
610// End: //
Note: See TracBrowser for help on using the repository browser.