
Hi all, At last I've managed to find some time to polish the Constrained Value library (former Constrained Types library) and want to share it to hear any opinions and suggestions. If all goes OK, I'll request a formal review when the library is completed. To remind what this library is about, an excerpt from the motivation section of documentation is attached at the bottom of this message. As for now, the implementation is complete, documentation is almost ready, tests and examples have to be finished. The code and documentation can be downloaded here: http://rk.go.pl/f/constrained_value.zip The documentation is also available online here: http://rk.go.pl/r/constrained_value Any feedback is very welcome! Best regards, Robert Kawulak FROM THE MOTIVATION SECTION OF DOCUMENTATION: The Boost Constrained Value library contains class templates useful for creating constrained objects. The simplest example of a constrained object is hour. The only valid values for an hour within a day are integers from the range [0, 23]. There's no C++ type which exactly matches this set of valid values, so a larger integral type (e.g. int) must be used to represent hours. But this can lead to errors -- for instance, one may accidentally assign an invalid value, say 26, to a variable holding an hour. The Boost Constrained Value library provides a mechanism protecting against such mistakes: bounded_int<int, 0, 23>::type hour; hour = 20; // OK hour = 26; // error -- throws an exception Another feature of the library is the ability to specify what happens in case of assignment of an invalid value. For instance, an exception may be thrown as in the example above, or the value may be adjusted to meet the constraint criterions: wrapping_int<int, 0, 255>::type buffer_index; buffer_index = 257; // OK -- adjusts the value to fit in the range by wrapping it assert(buffer_index == 1); The library doesn't focus only on constrained objects that hold a value belonging to a specified range (i.e., bounded objects). Virtually any constraint can be imposed using appropriate predicate: // constraint policy -- a predicate struct is_even { bool operator () (int i) const { return (i % 2) == 0; } }; // and the usage is as simple as: constrained<int, is_even>::type even_int; even_int = 2; // OK even_int++; // error -- throws an exception

Looks very interesting! One thing I'm noticing right off, is that there are concepts, such as "ConstAdaptableGenerator" referred to, but I'm not finding a definition of the concepts.

From: Neal Becker One thing I'm noticing right off, is that there are concepts, such as "ConstAdaptableGenerator" referred to, but I'm not finding a definition of the concepts.
Well, to be honest, I also haven't seen a formal definition of "ConstAdaptableGenerator" anywhere, but I was assuming that the reader can figure out that it's "AdaptableGenerator with const invocation operator" (by analogy to Const_BinaryPredicateConcept in Boost Concept Check Library). Would it be better if I change it to the latter? Are there any other things that are unclear or ambiguous? Best regards, Robert

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak Sent: 20 August 2007 18:35 To: boost@lists.boost.org Subject: [boost] Constrained Value library
Hi all,
At last I've managed to find some time to polish the Constrained Value library
Looks good (invaluable even) to me. 1 "The implementation heavily relies on the capability of a compiler to perform EBO (the Empty Base-class Optimization). Lack of this capability can decrease size (and possibly speed) performance of the generated code." Do you mean Lack of this capability can *increase* size and decrease performance...?? You could be specific about what Borland option is needed for EBO. 2 I don't see any examples with floating-point. Does this mean that it is only suitable for integral types? Could a floating-point type set to a NaN if out of bounds? 3 Some inline comments on the example could explain why some definitions are so verbose - for those who have yet to RTFM ;-) 4 Ready for review IMO. Paul --- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539561830 & SMS, Mobile +44 7714 330204 & SMS pbristow@hetp.u-net.com

From: Paul A Bristow
1 "The implementation heavily relies on the capability of a compiler to perform EBO (the Empty Base-class Optimization). Lack of this capability can decrease size (and possibly speed) performance of the generated code."
Do you mean Lack of this capability can *increase* size and decrease performance...??
No, I meant it can decrease size performance and speed performance, but I'll rewrite the sentence to be more clear. ;-)
You could be specific about what Borland option is needed for EBO.
Good point. By the way, are there users of some current versions of Borland? Does this still hold that the '-Ve' switch has to be used?
2 I don't see any examples with floating-point. Does this mean that it is only suitable for integral types? Could a floating-point type set to a NaN if out of bounds?
Any value type with 'normal' semantics can be used (with exception of wrapping - the underlying type must represent integers, although not necessarily integral) -- see examples with strings. The problem with floats is that they are not 'normal' - see http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17. Therefore this may make it impossible for constrained float to guarantee its invariant (I'm not completely sure about this, but at least extreme care should be taken when trying to use float as constrained underlying value). I'll add a note on this issue.
3 Some inline comments on the example could explain why some definitions are so verbose - for those who have yet to RTFM ;-)
Which particular definitions you mean? Thanks a lot for help, Robert

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak Sent: 21 August 2007 16:11 To: boost@lists.boost.org Subject: Re: [boost] Constrained Value library
3 Some inline comments on the example could explain why some definitions are so verbose - for those who have yet to RTFM ;-)
Which particular definitions you mean?
Some definitions are one-liners and pretty obvious. It's less obvious (until you read the manual!) why other definitions takes 6 lines ;-) Paul

Hi all, I've just written a draft of constraint policy, error policy and aliases for constrained types with a predefined error value. When the constraint is broken, the error policy changes the value to the selected value indicating error. Examples are attached below. Does it look useful enough to be worth adding to the library? Best regards, Robert P.S. Note, that when the error value is set, all the operations are still allowed. Making a constrained type that ignores all subsequent operations once the error value has been set is not easy given the current design and would require a serious redesign of the policies, making them more complicated. // typical bounded_errval_int usage // parameters: value type, error value, lower bound, upper bound (default used for the rest) // note: error value is NOT in the allowed range (but could be) bounded_errval_int<int, -1, 0, 100>::type b; BOOST_CHECK(b == 0); b = 1; BOOST_CHECK(b == 1); b = 1000; BOOST_CHECK(b == -1); b--; BOOST_CHECK(b == -1); b++; // mind this - error value can be changed this way too BOOST_CHECK(b == 0); b = -1; BOOST_CHECK(b == -1); // initialized with invalid value of 0 BOOST_CHECK((bounded_errval_int<int, -1, 10, 15>::type() == -1)); // initialized with the error value itself BOOST_CHECK((bounded_errval_int<int, 0, 10, 15>::type() == 0)); // custom constraint // parameters: value type, error value, constraint (default used for the rest) // note: error value is a value allowed by the predicate constrained_errval_int<int, 0, is_even>::type ei0; BOOST_CHECK(ei0 == 0); ei0 = 2; BOOST_CHECK(ei0 == 2); ei0 = 3; BOOST_CHECK(ei0 == 0); ei0 += 4; BOOST_CHECK(ei0 == 4); ei0 -= 3; BOOST_CHECK(ei0 == 0); ei0++; BOOST_CHECK(ei0 == 0); // note: error value is a value NOT allowed by the predicate constrained_errval_int<int, 1, is_even>::type ei1(3); BOOST_CHECK(ei1 == 1); ei1 = 2; BOOST_CHECK(ei1 == 2); ei1 = 3; BOOST_CHECK(ei1 == 1); ei1 += 4; BOOST_CHECK(ei1 == 1); ei1 -= 3; BOOST_CHECK(ei1 == -2); ei1++; BOOST_CHECK(ei1 == 1);

Robert Kawulak <tigrisek <at> interia.pl> writes:
bounded_int<int, 0, 23>::type hour; hour = 20; // OK hour = 26; // error -- throws an exception
I think the design of the interface is an example of taking generic programming too far. Making the constraints/predicates template parameters would have the limitations that only state-less functors and compile-time constraints could be accepted. This can be unacceptable, if, for instance, my predicate is a state-ful functor, or if it's a binded function (e.g. boost::bind(f, _1, x) ). So why not generalize the interface using boost::function, like this: template<typename T> class constraint_data { public: typedef boost::function<bool(T const&)> constraint_t; ... void add_constraint(constraint_t constraint); private: ... std::vector<constraint_t> v; }; We can have add_constraints and var-arg constructors when C++09 is out: constraint_data(std::initializer_list<constraint_t> list){ ... }

From: pongba I think the design of the interface is an example of taking generic programming too far. Making the constraints/predicates template parameters would have the limitations that only state-less functors and compile-time constraints could be accepted.
This is not true - have you looked at the constrained class template (for which bounded_int is only an alias)? It can accept any predicate type (stateful or not) and you can modify it at runtime.
This can be unacceptable, if, for instance, my predicate is a state-ful functor, or if it's a binded function (e.g. boost::bind(f, _1, x) ). So why not generalize the interface using boost::function, like this:
[snip] Why not just use constrained< T, boost::function1<bool, T> >? I attach an example below. Best regards, Robert struct is_even { bool operator () (int i) const { return (i % 2) == 0; } } is_even_fn; std::binder1st< std::less<int> > is_positive_fn(std::less<int>(), 0); int test_main(int, char*[]) { // object constrained by any predicate constrained< int, boost::function1<bool, int> > c(is_even_fn); BOOST_CHECK(c.value() == 0); // set to negative value THIS_IS_OK_(c = -2); BOOST_CHECK(c.value() == -2); // cannot change constraint -- the value // is not conforming to is_positive_fn THIS_FAILS_(change_constraint(c, is_positive_fn)); BOOST_CHECK(c.value() == -2); // set to positive value THIS_IS_OK_(c = 2); BOOST_CHECK(c.value() == 2); // now can change the constraint THIS_IS_OK_(change_constraint(c, is_positive_fn)); BOOST_CHECK(c.value() == 2); // now only positive numbers THIS_IS_OK_(c = 1); BOOST_CHECK(c.value() == 1); THIS_FAILS_(c = -2); BOOST_CHECK(c.value() == 1); return 0; } NB: value() call is needed in comparisons, because constrained op == interferes with function1 op == -- that's the disadvantage of using EBO.

From: Robert Kawulak
struct is_even { bool operator () (int i) const { return (i % 2) == 0; } } is_even_fn;
Actually, this could even be bool is_even_fn(int i) { return (i % 2) == 0; }
constrained< int, boost::function1<bool, int> > c(is_even_fn);
Now I'm thinking about making boost::function1 the default parameter of constrained, so you could just write constrained<int> c(is_even_fn); Looks good, doesn't it: :D Best regards, Robert

Any hints? #include <boost/constrained_value/constrained.hpp> #include <boost/constrained_value/bounded_aliases.hpp> #include <iostream> int main() { using namespace std; using namespace boost::constrained_value; bounded_int<int, 0, 23>::type hour; hour = 0; hour = 23; saturating_int<int, 0, 23>::type hour2; hour2 = 24; <<< this is the line that gave an error cout << hour << '\t' << hour2 << '\n'; return 0; } [...] test/test_bound.cc:14: instantiated from here/usr/local/src/boost.hg/boost/constrained_value/bounded_error_handlers.hpp:86: error: 'is_above' was not declared in this scope

From: Neal Becker test/test_bound.cc:14: instantiated from here/usr/local/src/boost.hg/boost/constrained_value/bounded_er ror_handlers.hpp:86: error: 'is_above' was not declared in this scope
Thanks for spotting, it's a typo in bounded_error_handlers.hpp:86 - should be: else if( c.is_above(nv) ) Best regards, Robert

Sorry if this is not the sort of question to ask on this mailing list but... ...I'm very interested in both constrained and saturated values but for the life of me I can't find the files mentioned in this discussion - could someone please tell me how to obtain them? Cheers -- Martin
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Robert Kawulak Sent: 24 August 2007 13:55 To: boost@lists.boost.org Subject: Re: [boost] Constrained Value library
*** WARNING ***
This mail has originated outside your organization, either from an external partner or the Global Internet. Keep this in mind if you answer this message.
From: Neal Becker test/test_bound.cc:14: instantiated from here/usr/local/src/boost.hg/boost/constrained_value/bounded_er ror_handlers.hpp:86: error: 'is_above' was not declared in this scope
Thanks for spotting, it's a typo in bounded_error_handlers.hpp:86 - should be:
else if( c.is_above(nv) )
Best regards, Robert
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
SELEX Sensors and Airborne Systems Limited Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL A company registered in England & Wales. Company no. 02426132 ******************************************************************** This email and any attachments are confidential to the intended recipient and may also be privileged. If you are not the intended recipient please delete it from your system and notify the sender. You should not copy it or use it for any purpose nor disclose or distribute its contents to any other person. ********************************************************************

From: Dowie, Martin (SELEX) (UK) I can't find the files mentioned in this discussion - could someone please tell me how to obtain them?
The links were found in the first post on this topic - here you go. ;-) The code and documentation can be downloaded here: http://rk.go.pl/f/constrained_value.zip The documentation is also available online here: http://rk.go.pl/r/constrained_value Best regards, Robert

Why does bounded_int have parameters: bool LowerIncluded = true, bool UpperIncluded = true, But saturating_int does not have these parameters?

From: Neal Becker Why does bounded_int have parameters: bool LowerIncluded = true, bool UpperIncluded = true, But saturating_int does not have these parameters?
Saturating bounded objects make sense only for closed ranges - how could a saturating object be assigned a value of one of the bounds on out-of-bounds assignment, if the bounds would be excluded from the allowed range, and thus not constraint-conforming? I'll add a note on this to the docs. ;-) Best regards, Robert
participants (6)
-
Dowie, Martin (SELEX) (UK)
-
Neal Becker
-
Paul A Bristow
-
pongba
-
Robert Kawulak
-
Robert Kawulak