source: src/Common/utility.h@ 692c1cc

ADT ast-experimental
Last change on this file since 692c1cc 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
RevLine 
[51587aa]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//
[60089f4]7// utility.h --
[51587aa]8//
9// Author : Richard C. Bilson
10// Created On : Mon May 18 07:44:20 2015
[298fe57]11// Last Modified By : Andrew Beach
[4b60b28]12// Last Modified On : Thr Feb 16 12:35:00 2023
13// Update Count : 52
[51587aa]14//
[01aeade]15
[6b0b624]16#pragma once
[51b73452]17
[234b1cb]18#include <cassert>
[e491159]19#include <cctype>
[940bba3]20#include <algorithm>
[2e30d47]21#include <functional>
[51b73452]22#include <iostream>
23#include <iterator>
24#include <list>
[e491159]25#include <memory>
26#include <sstream>
27#include <string>
[55a68c3]28#include <type_traits>
[fbecee5]29#include <utility>
[234b1cb]30#include <vector>
[8abca06]31#include <cstring> // memcmp
[be9288a]32
[50377a4]33#include "Common/Indenter.h"
34
[5cbacf1]35class Expression;
36
[c1ed2ee]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
[51b73452]44template< typename T >
[01aeade]45static inline T * maybeClone( const T *orig ) {
46 if ( orig ) {
47 return orig->clone();
48 } else {
49 return 0;
50 } // if
[51b73452]51}
52
53template< typename Input_iterator >
[01aeade]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
[51b73452]58}
59
60template< typename Container >
[8abee136]61void deleteAll( const Container &container ) {
62 for ( const auto &i : container ) {
63 delete i;
[01aeade]64 } // for
[51b73452]65}
66
67template< typename Container >
[50377a4]68void printAll( const Container &container, std::ostream &os, Indenter indent = {} ) {
[01aeade]69 for ( typename Container::const_iterator i = container.begin(); i != container.end(); ++i ) {
70 if ( *i ) {
[50377a4]71 os << indent;
72 (*i)->print( os, indent );
[60089f4]73 // need an endl after each element because it's not easy to know when each individual item should end
[01aeade]74 os << std::endl;
75 } // if
76 } // for
[51b73452]77}
78
79template< typename SrcContainer, typename DestContainer >
[01aeade]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
[51b73452]86}
87
[54c9000]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
[51b73452]98template< typename Container >
[01aeade]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
[51b73452]108template < typename T >
[01aeade]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
[51b73452]114}
115
116template < typename T >
117std::list<T> flatten( std::list < std::list<T> > l) {
[01aeade]118 typedef std::list <T> Ts;
[51b73452]119
[01aeade]120 Ts ret;
[51b73452]121
[a08ba92]122 switch ( l.size() ) {
[01aeade]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
[51b73452]132}
133
[234b1cb]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
[60089f4]149template < typename T >
[2298f728]150void toString_single( std::ostream & os, const T & value ) {
[79970ed]151 os << value;
152}
153
154template < typename T, typename... Params >
[2298f728]155void toString_single( std::ostream & os, const T & value, const Params & ... params ) {
[79970ed]156 os << value;
157 toString_single( os, params ... );
158}
159
160template < typename ... Params >
[2298f728]161std::string toString( const Params & ... params ) {
[5f2f2d7]162 std::ostringstream os;
[79970ed]163 toString_single( os, params... );
[5f2f2d7]164 return os.str();
[51b73452]165}
166
[babeeda]167#define toCString( ... ) toString( __VA_ARGS__ ).c_str()
168
[3c13c03]169// replace element of list with all elements of another list
[51b73452]170template< typename T >
171void replace( std::list< T > &org, typename std::list< T >::iterator pos, std::list< T > &with ) {
[01aeade]172 typename std::list< T >::iterator next = pos; advance( next, 1 );
[51b73452]173
[01aeade]174 //if ( next != org.end() ) {
[a08ba92]175 org.erase( pos );
176 org.splice( next, with );
177 //}
[51b73452]178
[01aeade]179 return;
[51b73452]180}
181
[3c13c03]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
[940bba3]189template< typename... Args >
190auto filter(Args&&... args) -> decltype(std::copy_if(std::forward<Args>(args)...)) {
191 return std::copy_if(std::forward<Args>(args)...);
[51b73452]192}
193
[2bf9c37]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
[298fe57]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
[940bba3]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);
[51b73452]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 ) {
[01aeade]222 while ( b1 != e1 && b2 != e2 )
223 *out++ = func(*b1++, *b2++);
[51b73452]224}
225
[d939274]226// it's nice to actually be able to increment iterators by an arbitrary amount
[940bba3]227template< class InputIt, class Distance >
228InputIt operator+( InputIt it, Distance n ) {
229 advance(it, n);
230 return it;
[d939274]231}
232
[79970ed]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
[8abca06]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 ) {
[bc3127d]252 if ( pref.size() > str.size() ) return false;
[8abca06]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
[bc3127d]255}
256
[940bba3]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
[e491159]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
[1f75e2d]277template< typename ThisType >
278std::weak_ptr<ThisType> RefCountSingleton<ThisType>::global_instance;
279
[940bba3]280// -----------------------------------------------------------------------------
[c8dfcd3]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
[134322e]295template< typename T >
296struct ValueGuardPtr {
297 T old;
298 T* ref;
299
300 ValueGuardPtr(T * inRef) : old( inRef ? *inRef : T() ), ref(inRef) {}
[1b65595]301 ValueGuardPtr(const ValueGuardPtr& other) = delete;
302 ValueGuardPtr(ValueGuardPtr&& other) : old(other.old), ref(other.ref) { other.ref = nullptr; }
[134322e]303 ~ValueGuardPtr() { if( ref ) *ref = old; }
304};
305
[234223f]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
[134322e]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
[940bba3]336// -----------------------------------------------------------------------------
337// Helper struct and function to support
338// for ( val : reverseIterate( container ) ) {}
339// syntax to have a for each that iterates backwards
340
[44f6341]341template< typename T >
[4a9ccc3]342struct reverse_iterate_t {
[44f6341]343 T& ref;
344
[4a9ccc3]345 reverse_iterate_t( T & ref ) : ref(ref) {}
[44f6341]346
[490fb92e]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(); }
[44f6341]351};
352
353template< typename T >
[4a9ccc3]354reverse_iterate_t< T > reverseIterate( T & ref ) {
355 return reverse_iterate_t< T >( ref );
[44f6341]356}
357
[f8143a6]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
[3ad7978]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
[4a9ccc3]430// -----------------------------------------------------------------------------
[5ce0659]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
[7491f97]440 // Getting the iterator and value types this way preserves const.
[5ce0659]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
[7491f97]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... ) {}
[5ce0659]456 base_iterator operator++() {
[7491f97]457 return base_iterator( ++std::get<Indices>( iterators )... );
[5ce0659]458 }
459 bool operator!=( const base_iterator& other ) const {
460 return iterators != other.iterators;
461 }
462 value_type operator*() const {
[7491f97]463 return std::tie( *std::get<Indices>( iterators )... );
[5ce0659]464 }
[6411b7d]465
[5ce0659]466 static base_iterator make_begin( Iterables & data ) {
[7491f97]467 return base_iterator( std::get<Indices>( data ).begin()... );
[5ce0659]468 }
469 static base_iterator make_end( Iterables & data ) {
[7491f97]470 return base_iterator( std::get<Indices>( data ).end()... );
[4a9ccc3]471 }
472 };
[50377a4]473
[6411b7d]474public:
[5ce0659]475 group_iterate_t( const Args &... args ) : iterables( args... ) {}
[6411b7d]476
[5ce0659]477 using iterator = base_iterator<decltype(
478 std::make_integer_sequence<std::size_t, sizeof...(Args)>())>;
[6411b7d]479
[5ce0659]480 iterator begin() { return iterator::make_begin( iterables ); }
481 iterator end() { return iterator::make_end( iterables ); }
[6411b7d]482};
483
[5ce0659]484// Helpers for the bounds checks (the non-varatic part of group_iterate):
[6411b7d]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
[5ce0659]497/// Performs bounds check to ensure that all arguments are of the same length.
[4a9ccc3]498template< typename... Args >
[55a68c3]499group_iterate_t<Args...> group_iterate( Args &&... args ) {
[6411b7d]500 runGroupBoundsCheck( args.size()... );
501 return group_iterate_t<Args...>( std::forward<Args>( args )... );
[6d267ca]502}
503
[5ce0659]504/// Does not perform a bounds check - requires user to ensure that iteration terminates when appropriate.
[6d267ca]505template< typename... Args >
506group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
[6411b7d]507 return group_iterate_t<Args...>( std::forward<Args>( args )... );
[4a9ccc3]508}
[294647b]509
[108f3cdb]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 {
[4639b0d]516 const T & ref;
517 std::function<Func> f;
[108f3cdb]518
519 struct iterator {
520 typedef decltype(begin(ref)) Iter;
521 Iter it;
[4639b0d]522 std::function<Func> f;
523 iterator( Iter it, std::function<Func> f ) : it(it), f(f) {}
[108f3cdb]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
[4639b0d]531 lambda_iterate_t( const T & ref, std::function<Func> f ) : ref(ref), f(f) {}
[108f3cdb]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 >
[4639b0d]538lambda_iterate_t<Args...> lazy_map( const Args &... args ) {
539 return lambda_iterate_t<Args...>( args...);
[108f3cdb]540}
541
[9dc31c10]542// -----------------------------------------------------------------------------
[f14d956]543// O(1) polymorphic integer ilog2, using clz, which returns the number of leading 0-bits, starting at the most
[9dc31c10]544// significant bit (single instruction on x86)
545
546template<typename T>
[d28a03e]547inline
[b6d7f44]548#if defined(__GNUC__) && __GNUC__ > 4
[d28a03e]549constexpr
550#endif
551T ilog2(const T & t) {
552 if(std::is_integral<T>::value) {
[9dc31c10]553 const constexpr int r = sizeof(t) * __CHAR_BIT__ - 1;
[d28a03e]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);
[9dc31c10]559 return -1;
[01b8ccf1]560} // ilog2
[108f3cdb]561
[5cbacf1]562// -----------------------------------------------------------------------------
563/// evaluates expr as a long long int. If second is false, expr could not be evaluated
[77d2432]564std::pair<long long int, bool> eval(const Expression * expr);
[108f3cdb]565
[87701b6]566namespace ast {
567 class Expr;
568}
569
570std::pair<long long int, bool> eval(const ast::Expr * expr);
571
[fbecee5]572// -----------------------------------------------------------------------------
[87701b6]573/// Reorders the input range in-place so that the minimal-value elements according to the
574/// comparator are in front;
[fbecee5]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;
[87701b6]579
[fbecee5]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
[51587aa]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.