$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Nathan Myers (ncm-yahoospam_at_[hidden])
Date: 2001-12-28 16:25:17
On Thu, 27 Dec 2001 13:53:27 -0500, "Beman Dawes" <bdawes_at_[hidden]> wrote:
> At 03:55 AM 12/27/2001, Nathan wrote:
> 
>  >On Wed, 26 Dec 2001 20:05:14 -0500, "Beman Dawes" <bdawes_at_[hidden]> wrote:
>  >> Did you consider asserting or throwing on b < e precondition 
>  >> violations?
>  >
>  >As a precondition, it is a logical error to insert into the set elements
>  >that are already present.  The type std::set<> doesn't throw if you try
>  >to insert the same element again.
> 
> But std::set<> doesn't have a precondition that the element can't already 
> be present, and has very well defined (ignore the insert) behavior if it is 
> already present.
> 
> I understand the reluctance to throw, but what about asserting on any of 
> the preconditions where the complexity of testing the precondition is 
> minimal?  Sure it is just a QOI issue, but it does help users.
In practice the way you use these things is to insert a big range, and then
carve off pieces, returning them when you're finished.  You know that a range
isn't included because you know what you have and where you got it.
Testing for b > e, or b >= e, is easy and cheap, but is a very unlikely
error.  Checking has_all or !has_any is more likely to catch errors, but
is quite expensive.
>  >  Passing a range to std::set<> with the
>  >iterators reversed does not result in an exception.
> 
> No, but an implementation is free to assert on that, if detectable.
Do any?
>  >I cannot imagine how client code could respond meaningfully to such an
>  >exception.
> 
> For precondition violations, asserts are often better that exceptions.  But 
> there has been past discussion where people pointed out cases where assert 
> was desirable in debug builds, but they would like an exception in release 
> mode.
Mm, they won't get that from the regular STL components.
What exception would you suggest?  I am inclined to std::logic_error.
I have included some code to do the cheaper but less useful checks.
>  >> What is the rationale for the insert precondition !has_any(b, e),
>  >> and the erase precondition has_all(b, e)?  (I'm just curious and
>  >> not suggesting that looser preconditions would be better.)
>  >
>  >The preconditions radically simplify the logic of the insert and erase
>  >members.  They correspond, logically, to the requirement the same memory
>  >not be passed to free() twice.  More general functions that don't impose
>  >such preconditions must contain a loop.  They would be easy to add (along 
> 
>  >with general set union, intersection, and complement-intersection), and I
>  >expect that will happen eventually, but they would not be a substitute 
>  >for the more basic operations.
> 
> Understood.  You might want to add the above to Rationale or FAQ docs.
I will.
>  >> The portion of the license which reads "Permission is granted for
>  >> any use free of charge provided..." can be read two ways:
>  >> ...
>  >
>  >I have edited the license to eliminate any ambiguity:
>  >
>  >// Copyright 2001 by Nathan C. Myers <ncm-nospam_at_[hidden]>.
>  >// Permission is granted free of charge for any use provided that (1)
>  >// this copyright notice is retained unchanged in its entirety, and
>  >// (2) the author is indemnified, held harmless, and released from all
>  >// responsibility for any  consequences of such use.
>  >
>  >As I understand it this is the minimal license that allows unrestricted
>  >use without exposing me to liability.
> 
> Thanks for clarifying the wording.
> 
> When first looking at extent_set yesterday, I thought I'd once had a need 
> for something similar, but couldn't remember the details.  It has now come 
> back to me, but the half-open ranges would be a problem.
> 
> The problem was a QA audit program for a map database to determine if there 
> was overlap in house number ranges for various records representing 
> segments of a street.
> 
> Thus Bound would be a class named HouseNumber.  About 99% of the streets in 
> the US have unsigned numeric house numbers.  But the other 1% have 
> different numbering schemes, with very approximately 200 in common 
> use.  Thus HouseNumber isn't an integer, but rather a complex class capable 
> of dealing with the numbering schemes.
> 
> HouseNumber is "assignable, copyable, and equality-comparable, and 
> comparable using the Compare operation" but it doesn't have any increment() 
> or successor() operations because for some addressing schemes there is no 
> valid result possible from such an operation.  That means there isn't any 
> way to form a half-open range, at least not without changing HouseNumber.
> 
> A specific example would be single-character alphabetic house numbers 
> running from A to Z.  What is the half-open range?  Z doesn't have a 
> successor.
> 
> One solution would be to modify the HouseNumber class to add a successor, 
> with a special off-the-end value.  That's uncomfortable; why should a type 
> which meets the requirements still need modification?  There are also some 
> schemes with discontinuous (although orderable) schemes; they would be an 
> additional headache.
> 
> I guess the question this raises is whether or not a half-open range is the 
> best way to specify ranges for arbitrary types?  It's really natural for 
> iterators, but seems unnatural at least for the HouseNumber application.
> 
> Are there killer arguments in favor of half-open ranges for extent_set?
It bothered me too that the submitted version cannot represent membership of
MAXINT.  I have an implementation of extent_set using closed ranges, but it
requires both successor and predecessor functions (n + 1 and n - 1), which
had seemed to me to limit extent_set<>'s application more than the half-open
ranges.  (Either would work fine for my purposes.)  Of course, instead of
literally "n + 1", it says "this->succ(n)", invoking an instantiation of 
a template argument.  That makes the interface a little more complicated.
I have posted the closed-range implementation in the files section, under 
the names "extent_set-0.2.tgz" and "extent_set-0_2.zip". See
  http://groups.yahoo.com/group/boost/files/extent_set/
It includes tests to ensure that the predecessor and successor functions
never try to generate a value that exceeds the range of the argument type.
Please let me know if you like it better.
Nathan Myers
ncm at cantrip dot org