Aldy Hernandez <al...@redhat.com> writes: > On 06/20/2017 10:59 AM, Martin Sebor wrote: >> On 06/20/2017 02:41 AM, Aldy Hernandez wrote: >>> On 05/23/2017 03:26 PM, Martin Sebor wrote: >>>> On 05/23/2017 04:48 AM, Aldy Hernandez wrote: >>> >>>> + void Union (wide_int x, wide_int y); >>>> + bool Union (const irange &r); >>>> + bool Union (const irange &r1, const irange &r2); >>>> + >>>> + // THIS = THIS ^ [X,Y]. Return TRUE if result is non-empty. >>>> + bool Intersect (wide_int x, wide_int y, bool readonly = false); >>>> + // THIS = THIS ^ R. Return TRUE if result is non-empty. >>>> + // THIS = R1 ^ R2. Return TRUE if result is non-empty. >>>> + bool Intersect (const irange &r1, const irange &r2, bool readonly = >>>> false); >>>> + // Return TRUE if THIS ^ R will be non-empty. >>>> + bool Intersect_p (const irange &r) >>>> + { return Intersect (r, /*readonly=*/true); } >>>> >>>> I would suggest the following changes to Union, Intersect, and Not: >>>> >>>> 1) Define all three members without the readonly argument and >>>> returning irange& (i.e., *this). The return value can be >>>> used wherever irange& is expected, and the is_empty() member >>>> function can be called on it to obtain the same result. E.g., >>>> Intersect A with B, storing the result in A: >>>> >>>> irange A, B; >>>> if (A.Intersect (B).is_empty ()) { ... } >>>> >>>> 2) Add non-members like so: >>>> >>>> irange range_union (const irange &lhs, const irange &rhs) >>>> { >>>> return irange (lhs).Union (rhs); >>>> } >>>> >>>> and find out if the union of A or B is empty without modifying >>>> either argument: >>>> >>>> irange A, B; >>>> if (range_union (A, B).is_empty ()) { ... } >>> >>> Perhaps we could provide an implicit conversion from irange to bool such >>> that we could write: >>> >>> if (range_union (A, B)) { ... } >>> >>> as well as being able to write: >>> >>> if (!range_union (A, B).is_empty ()) { ... } >>> >>> That is, have range_union() return an irange as suggested, but have a >>> bool overload (or whatever the C++ nomenclature is) such that converting >>> an irange to a bool is interpreted as ``nitems != 0''. >>> >>> Is this acceptable C++ practice? >> >> Implicit conversion to bool is a common way of testing validity >> but I don't think it would be too surprising to use it as a test >> for non-emptiness. An alternative to consider is to provide >> an implicit conversion to an unsigned integer (instead of >> num_ranges()(*)) and have it return the number of ranges. That >> will make it possible to do the same thing as above while also >> simplifying the API. > > I really like this. > > I have added an implicit conversion to unsigned that returns the number > of sub-ranges. However, I have also left the empty_p() method for a > cleaner interface within the class itself. It feels wrong to type "if > (!*this)" to represent emptiness within the class.
Conversions to bool and conversions to int both seem dangerous. E.g. people might try "range1 | range2" as a shorthand for taking the union of the ranges. It'll compile but instead give the bitwise OR of the two range counts. How about instead having helper functions like intersect_p, as for bitmaps? Thanks, Richard