[xint] Third release is ready, requesting preliminary review

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. This is a major overhaul of the library, taking into account all of the feedback and recommendations provided on the first two: * The exception-blocking system is gone, replaced by a separate nothrow_integer class. * There's now a fixed_integer class template as well. * The test functions now use Boost.Test, and the documentation has been moved to Doxygen. * Nearly every function received a thorough examination as well; many of them were tweaked, and a few completely replaced. Please take a look and let me know what you think of the changes. I'm very happy with them. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvabA0ACgkQp9x9jeZ9/wSwvACcCJ18QkRbKWmByYO7Q1xe6qYx EUYAnRl4+mzw9X2VvGCCFPl0Q0VWLhRN =fhbW -----END PGP SIGNATURE-----

It would be good to remind us what this is

Neal Becker wrote:
It would be good to remind us what this is
...and where. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 04/30/2010 07:11 AM, Stewart, Robert wrote:
Neal Becker wrote:
It would be good to remind us what this is
...and where.
Sorry, I thought "sandbox and Vault" would be sufficient to locate it. The sandbox address is <https://svn.boost.org/svn/boost/sandbox/xint>; the Vault one is <http://www.boostpro.com/vault/index.php?action=downloadfile&filename=xint.zip&directory=&>. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkva5+4ACgkQp9x9jeZ9/wRCNQCeLQEf67UK0QSFtJfckuQOe6OU vM0AoOjB1QrsuFe9xDzzGfsgGpReq66l =5+NT -----END PGP SIGNATURE-----

Chad Nelson wrote:
The sandbox address is <https://svn.boost.org/svn/boost/sandbox/xint>;
_______________________ xint.hpp xint.hpp surprised me. Typically, for Boost anyway, such a header is a convenience for library users that don't wish to be more specific about the headers they include. However, xint.hpp includes something surprising: internals.hpp. I would have expected the other headers to have included internals.hpp if needed. _______________________ integer.hpp Your use of enable_if could be simplified into a single argument for the integer constructors by using mpl::and_. The integer member function template assignment operator could benefit from the advice in <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>. There may well be other member functions that should be changed as well. integer::operator -() should not be a member function. Only operator -=() need be. Why is integer::operator +() defined to return *this? That operator should return a new instance (and need not be a member). The "not recommended, inefficient" comment for postincrement and postdecrement sounds too harsh. It is well known that those operations are costlier than preincrement and predecrement. You docstring can simply discuss the inefficiency in terms of memory allocations, data copying, etc. and leave the decision to the library user. The post- operators should not be member functions. integer::operator <<() and operator >>() should not be member functions. Only the shift-and-assign variants need be members. ISTR someone mentioning this before, but I'll reiterate: "odd" and "even" are not good names for predicates. Prepend "is_" to them. sqr() means, I suppose, square, since you have sqrt(), too. Why not spell it out and remove doubt? from_string() doesn't provide a strtol()-style interface in that one cannot know whether the entire string was consumed during parsing. An overload for char const * would be appropriate so as to avoid forcing the creation of a std::string when not already available. from_string() and from_binary() should be named "to_integer" in keeping with to_string() and because they can be overloaded. mod(), at the least among the modulus functions, is widely applicable, so the docstring tying those functions to encryption is a bit misleading. It looks as if you haven't taken advantage of building some of the relational operators on the others. For example, >= is !<. That is, many of the operators should be inlined and only a few need to be implemented. s/template function/function template/ The docstring for parameter n in the T constructor (integer::integer(T const &, /* enable_if noise */)) should be "The value of the new instance" or something along those lines. As it stands, the \param and \tparam text is circular. I find it curious that the docstrings are split such that some are in the class definition and others are not. I realize that Doxygen extracts them, but I still expect to see them in the class definition. If you prefer them on the function definitions, then perhaps you could avoid defining any functions within the class definition. Commentary, like "efficiently" in the to() docstring, should be left for broader library documentation. exceptions::too_big sounds like std::range_error to me. ::operator <<() is implemented in terms of detail::operator <<() (and similar for >>). The function in the detail namespace should probably just be called "stream" or something of that sort, don't you think? ____________________ I may look at the other headers in the near future, but there should be good food for thought in this much. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 10:27 AM, Stewart, Robert wrote:
_______________________ xint.hpp
xint.hpp surprised me. Typically, for Boost anyway, such a header is a convenience for library users that don't wish to be more specific about the headers they include. However, xint.hpp includes something surprising: internals.hpp. I would have expected the other headers to have included internals.hpp if needed.
They do. I put it there thinking that it might keep at least some compilers from looking at it again. It probably doesn't matter either way though. I'll remove it.
_______________________ integer.hpp
Your use of enable_if could be simplified into a single argument for the integer constructors by using mpl::and_.
Thanks for the suggestion, but I'd like to keep the dependencies and compile times at a minimum. I'm also not familiar with mpl yet... I'll look at it at some point, but I'd rather concentrate on XInt itself for now. The time I can devote to it is limited.
The integer member function template assignment operator could benefit from the advice in <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>. There may well be other member functions that should be changed as well.
I read it when you first mentioned it (though not in detail), but I'm deferring everything related to that until I determine whether copy-on-write is going to be used in the final version of the library. If it is, then passing by value is cheap in all cases, and is probably best; if not, then it might be better to leave most functions using const references instead, because I'm not convinced that the compiler will have a chance to optimize the copies away in most cases.
integer::operator -() should not be a member function. Only operator -=() need be.
The unary operator- doesn't need to be a member function, but I see no reason why it shouldn't.
Why is integer::operator +() defined to return *this? That operator should return a new instance
Why?
(and need not be a member).
I had unary operator- and operator+ as free functions originally, but the compiler got confused about them when I added the fixed_integer template type. I don't recall the details of what confused it, but making them member functions of fixed_integer was a natural solution to the problem, and it seemed discordant to leave the corresponding functions for the integer and nothrow_integer types as free functions when fixed_integer had them as member functions.
The "not recommended, inefficient" comment for postincrement and postdecrement sounds too harsh. [...]
Not as harsh as not implementing them at all, which is what n1692 recommended. I prefer to implement all of the operators, and leave the decision to the person using the library, with a warning so that he knows to think before using them.
The post- operators should not be member functions.
Again, why?
integer::operator <<() and operator >>() should not be member functions. Only the shift-and-assign variants need be members.
Only those variants *need* to be members, but the others *can* be members. There's no advantage either way for the ones that I've made members, so far as I know. Unlike the binary operator+ for example, which potentially gains the ability to operate if the second parameter is the type and the first parameter is convertible to it. As such, I consider it personal preference.
ISTR someone mentioning this before, but I'll reiterate: "odd" and "even" are not good names for predicates. Prepend "is_" to them.
As I said when it was recommended before, those names were recommended in n1692. I plan to change them, since the is_ names *are* better and I've already broken full compatibility with that document in numerous small ways anyway, but it hasn't been a priority yet.
sqr() means, I suppose, square, since you have sqrt(), too. Why not spell it out and remove doubt?
I had a lot of functions, including both of those, spelled out in earlier iterations of the library. I changed them to match the conventions of similar functions in the C and C++ libraries, on the assumption that people would find them easier to remember that way.
from_string() doesn't provide a strtol()-style interface in that one cannot know whether the entire string was consumed during parsing.
Not quite true. If the string contains any characters that can't be converted, it throws an exception. If it gets to the point of returning a value at all, then all characters were consumed. If you need to parse out the characters that are actually part of a number, like strtol, the stream functions will do that. At least for base 8, 10, and 16 numbers, which I expect will be the main ones that people will use anyway.
An overload for char const * would be appropriate so as to avoid forcing the creation of a std::string when not already available.
I was under the impression that a char* would be efficiently converted to a const std::string& when needed. If it's less efficient than I was led to believe, then I'll certainly add an overload.
from_string() and from_binary() should be named "to_integer" in keeping with to_string() and because they can be overloaded.
Hm... yes, that might be slightly better. Added to the to-do list.
mod(), at the least among the modulus functions, is widely applicable, so the docstring tying those functions to encryption is a bit misleading.
True enough. I'll move it to the primitives.
It looks as if you haven't taken advantage of building some of the relational operators on the others. For example, >= is !<. That is, many of the operators should be inlined and only a few need to be implemented.
I'm not sure I see your point. They all consist of a single function call and an int comparison, so the compiler will probably inline them regardless.
s/template function/function template/
Where do you see them? grep doesn't find the string "template function" anywhere in the source, headers, or documentation. And out of curiosity, do they have different meanings that I'm not aware of, or is this just the commonly-used phrasing?
The docstring for parameter n in the T constructor (integer::integer(T const &, /* enable_if noise */)) should be "The value of the new instance" or something along those lines. As it stands, the \param and \tparam text is circular.
Sure, if it's clearer to you. The circular reference seemed perfectly clear to me.
I find it curious that the docstrings are split such that some are in the class definition and others are not. I realize that Doxygen extracts them, but I still expect to see them in the class definition. If you prefer them on the function definitions, then perhaps you could avoid defining any functions within the class definition.
My rule (which I don't follow religiously) is that the Doxygen information for individual functions is just above their implementations, and the Doxygen information for groups of functions (member or free) is above their declarations.
Commentary, like "efficiently" in the to() docstring, should be left for broader library documentation.
Why? It's far more efficient than the method that would almost certainly otherwise be used, which is to stream it out and stream it back to the new type, and I wanted to make that clear. I'm also not sure what broader library documentation you're talking about.
exceptions::too_big sounds like std::range_error to me.
The wording on std::range_error, in Josuttis' "The C++ Standard Library", is that it's "used to report a range error in internal computations." That didn't quite sound like what I was trying to convey with that exception, which is that the library type that the user is trying to convert won't fit into the type that he's trying to convert it to. It does inherit from std::range_error though.
::operator <<() is implemented in terms of detail::operator <<() (and similar for >>). The function in the detail namespace should probably just be called "stream" or something of that sort, don't you think?
Tomayto, tomahto. :-) I used the operator names because that's what they're solely used from, and for. It seemed clearer than giving the version in the detail namespace a different name.
____________________
I may look at the other headers in the near future, but there should be good food for thought in this much.
Thank you. Despite the objections that I raised to most of the items, I do appreciate it. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvgVbsACgkQp9x9jeZ9/wTIvgCg3ruldS4Qhx73LIecVuWqK11n a7wAn2Lo/+H0jFDXVuUgPr1PACCRmFo0 =0QGP -----END PGP SIGNATURE-----

On 5/4/2010 10:13 AM, Chad Nelson wrote:
On 05/04/2010 10:27 AM, Stewart, Robert wrote:
_______________________ integer.hpp
Your use of enable_if could be simplified into a single argument for the integer constructors by using mpl::and_.
Thanks for the suggestion, but I'd like to keep the dependencies and compile times at a minimum. I'm also not familiar with mpl yet... I'll look at it at some point, but I'd rather concentrate on XInt itself for now. The time I can devote to it is limited.
IMHO, using multiple "typename enable_if<...>::type* = 0" in a constructor is just fine. It makes the clauses line up a little more uniformly (to me). Just remember, you'll have to use boost::mpl::and_ (or similar) if you need short-circuiting. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 01:17 PM, Jeffrey Lee Hellrung, Jr. wrote:
Your use of enable_if could be simplified into a single argument for the integer constructors by using mpl::and_.
Thanks for the suggestion, but I'd like to keep the dependencies and compile times at a minimum. [...]
IMHO, using multiple "typename enable_if<...>::type* = 0" in a constructor is just fine. It makes the clauses line up a little more uniformly (to me). Just remember, you'll have to use boost::mpl::and_ (or similar) if you need short-circuiting.
Thanks for the tip. I hadn't even considered a need to short-circuit the enable_if evaluations, or that there might be a way to do it if I had one. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvgWysACgkQp9x9jeZ9/wSXSQCeIyasIc5piDy1ddrJ/brNDDHC H8MAnRhkH9nENurfNk4zJjl4N0SQ20LH =pksq -----END PGP SIGNATURE-----

AMDG Jeffrey Lee Hellrung, Jr. wrote:
On 5/4/2010 10:13 AM, Chad Nelson wrote:
Thanks for the suggestion, but I'd like to keep the dependencies and compile times at a minimum. I'm also not familiar with mpl yet... I'll look at it at some point, but I'd rather concentrate on XInt itself for now. The time I can devote to it is limited.
IMHO, using multiple "typename enable_if<...>::type* = 0" in a constructor is just fine. It makes the clauses line up a little more uniformly (to me). Just remember, you'll have to use boost::mpl::and_ (or similar) if you need short-circuiting.
IIRC, Sun CC can break with multiple enable_ifs In Christ, Steven Watanabe

Chad Nelson wrote:
On 05/04/2010 10:27 AM, Stewart, Robert wrote:
The integer member function template assignment operator could benefit from the advice in <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>. There may well be other member functions that should be changed as well.
I read it when you first mentioned it (though not in detail), but I'm deferring everything related to that until I determine whether copy-on-write is going to be used in the final version of the library. If it is, then passing by value is cheap in all cases, and is probably best; if not, then it might be better to leave most functions using const references instead, because I'm not convinced that the compiler will have a chance to optimize the copies away in most cases.
If the compiler elides the argument copying, then the COW logic won't be invoked. It's a win with or without COW.
integer::operator -() should not be a member function. Only operator -=() need be.
The unary operator- doesn't need to be a member function, but I see no reason why it shouldn't.
Scott Meyers wrote on that some years ago. The principle is to keep everything out of the class that you can so that there's less to inspect whenever you alter the class' implementation. That is, if a non-member operator -() is built atop operator -=(), and you change the class implementation details, you only need to check for effects on operator -=().
Why is integer::operator +() defined to return *this? That operator should return a new instance
Why?
Um, because that operator is used for i + j and returns the sum, right? Did I miss something?
(and need not be a member).
I had unary operator- and operator+ as free functions originally, but the compiler got confused about them when I added the fixed_integer template type. I don't recall the details of what confused it, but making them member functions of fixed_integer was a natural solution to the problem, and it seemed discordant to leave the corresponding functions for the integer and nothrow_integer types as free functions when fixed_integer had them as member functions.
There's no harm in making those operators members, but the class definition shrinks which makes maintenance easier when they aren't. In this case, as a means to overcome what confused the compiler, at least as things stood at some point in time, I can understand your tack. For binary operators, you frequently need to implement some as non-members to allow for swapped argument order, so it makes sense to implement both variants as non-members in terms of the one assignment variation which must be a member.
The "not recommended, inefficient" comment for postincrement and postdecrement sounds too harsh. [...]
Not as harsh as not implementing them at all, which is what n1692 recommended. I prefer to implement all of the operators, and leave the decision to the person using the library, with a warning so that he knows to think before using them.
I think part of what you elided was a suggestion that information regarding the inefficiency be put where you can give it fair treatment, not in a terse, somewhat misleading docstring. I also noted that it should be the library user determining whether the cost is worthwhile.
sqr() means, I suppose, square, since you have sqrt(), too. Why not spell it out and remove doubt?
I had a lot of functions, including both of those, spelled out in earlier iterations of the library. I changed them to match the conventions of similar functions in the C and C++ libraries, on the assumption that people would find them easier to remember that way.
What does sqr() do?
from_string() doesn't provide a strtol()-style interface in that one cannot know whether the entire string was consumed during parsing.
Not quite true. If the string contains any characters that can't be converted, it throws an exception. If it gets to the point of returning a value at all, then all characters were consumed.
If you need to parse out the characters that are actually part of a number, like strtol, the stream functions will do that. At least for base 8, 10, and 16 numbers, which I expect will be the main ones that people will use anyway.
I'd prefer to have both forms. That is, if I call the overload which takes a non-const reference to an iterator or size_t, I can determine where the parsing left off and not get an exception. If I assume everything should parse, I'd use the current overload.
An overload for char const * would be appropriate so as to avoid forcing the creation of a std::string when not already available.
I was under the impression that a char* would be efficiently converted to a const std::string& when needed. If it's less efficient than I was led to believe, then I'll certainly add an overload.
std::string construction from a char * implies free store allocation and copying.
It looks as if you haven't taken advantage of building some of the relational operators on the others. For example, >= is !<. That is, many of the operators should be inlined and only a few need to be implemented.
I'm not sure I see your point. They all consist of a single function call and an int comparison, so the compiler will probably inline them regardless.
I didn't see the implementation of those, so I assumed that they were declarations of non-inlined functions. Nevertheless, this is another case of only having to worry about the implementation of a core set of functions and leave the others in terms of those.
s/template function/function template/
Where do you see them? grep doesn't find the string "template function" anywhere in the source, headers, or documentation.
Search case insensitively. I think it was "Template function" actually.
And out of curiosity, do they have different meanings that I'm not aware of, or is this just the commonly-used phrasing?
The correct terminology is "function template" and "class template." IOW, they are templates for generating functions or classes, they are not functions or classes.
Commentary, like "efficiently" in the to() docstring, should be left for broader library documentation.
Why? It's far more efficient than the method that would almost certainly otherwise be used, which is to stream it out and stream it back to the new type, and I wanted to make that clear. I'm also not sure what broader library documentation you're talking about.
First, I'm assuming that Doxygen generated documentation will be for reference and not for tutorial, rationale, etc. content. That is the "broader library documentation" to which I refer. Second, when describing what a function does, the word "efficiently" isn't helpful. If you prefer, you can discuss the efficiency aspects in the rest of the docstring (not part of the brief line).
exceptions::too_big sounds like std::range_error to me.
The wording on std::range_error, in Josuttis' "The C++ Standard Library", is that it's "used to report a range error in internal computations." That didn't quite sound like what I was trying to convey with that exception, which is that the library type that the user is trying to convert won't fit into the type that he's trying to convert it to. It does inherit from std::range_error though.
The name fits nicely, even if the description suggests something slightly different. Arguably, your internal computation determined that the value exceeded the range of the target type, so the exception type is fitting. In the end, there's no harm in having your own type, given that it does derive from range_error. It allows calling code to be more specific if warranted.
::operator <<() is implemented in terms of detail::operator <<() (and similar for >>). The function in the detail namespace should probably just be called "stream" or something of that sort, don't you think?
Tomayto, tomahto. :-) I used the operator names because that's what they're solely used from, and for. It seemed clearer than giving the version in the detail namespace a different name.
I just think calling operator functions by name to be awkward so I usually avoid it.
Thank you. Despite the objections that I raised to most of the items, I do appreciate it.
You're welcome. I didn't expect you to agree with everything, least of all the stylistic suggestions. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 5/4/2010 11:23 AM, Stewart, Robert wrote:
Chad Nelson wrote: [...]
Why is integer::operator +() defined to return *this? That operator should return a new instance
Why?
Um, because that operator is used for i + j and returns the sum, right? Did I miss something?
I suspect you (Robert) might be looking at the unary + operator... - Jeff

Jeffrey Lee Hellrung, Jr.
On 5/4/2010 11:23 AM, Stewart, Robert wrote:
Chad Nelson wrote: [...]
Why is integer::operator +() defined to return *this? That operator should return a new instance
Why?
Um, because that operator is used for i + j and returns the sum, right? Did I miss something?
I suspect you (Robert) might be looking at the unary + operator...
Doh! So I was. I didn't even look at the argument list when I saw it because I've never overloaded the unary +! _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 02:44 PM, Stewart, Robert wrote:
Um, because that operator is used for i + j and returns the sum, right? Did I miss something?
I suspect you (Robert) might be looking at the unary + operator...
Doh! So I was. I didn't even look at the argument list when I saw it because I've never overloaded the unary +!
I don't know anyone who does, but I assume that someone out there, someone will, and would be irritated if it didn't work the same as the built in integer types. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvguj4ACgkQp9x9jeZ9/wRLiwCgmi7LI2A5Ku/CSVCwJG7sZbC8 MKcAoPiS2br9yXa60yfMDt04nTMQbyqd =/fAi -----END PGP SIGNATURE-----

on 05.05.2010 at 4:22 Chad Nelson wrote :
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/04/2010 02:44 PM, Stewart, Robert wrote:
Um, because that operator is used for i + j and returns the sum, right? Did I miss something?
I suspect you (Robert) might be looking at the unary + operator...
Doh! So I was. I didn't even look at the argument list when I saw it because I've never overloaded the unary +!
I don't know anyone who does, but I assume that someone out there, someone will, and would be irritated if it didn't work the same as the built in integer types.
that person is me definitly -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/05/2010 01:37 PM, DE wrote:
Um, because that operator is used for i + j and returns the sum, right? Did I miss something?
I suspect you (Robert) might be looking at the unary + operator...
Doh! So I was. I didn't even look at the argument list when I saw it because I've never overloaded the unary +!
I don't know anyone who does, but I assume that someone out there, someone will, and would be irritated if it didn't work the same as the built in integer types.
that person is me definitly
I was just wishing, when I wrote that, that I did know someone who did that... purely out of curiosity, I wanted to ask why they (i.e. you) did that? Is it just to make it more obvious that it's supposed to be a positive number instead of a negative one? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvhxIgACgkQp9x9jeZ9/wQHwQCeNNN6/duASbCfwGiBdGH3vsvE 4doAn2yISlLUBsNXWqvdC7BoPRlznnTJ =k7dT -----END PGP SIGNATURE-----

on 05.05.2010 at 23:18 Chad Nelson wrote :
On 05/05/2010 01:37 PM, DE wrote:
I suspect you (Robert) might be looking at the unary + operator...
Doh! So I was. I didn't even look at the argument list when I saw it because I've never overloaded the unary +!
I don't know anyone who does, but I assume that someone out there, someone will, and would be irritated if it didn't work the same as the built in integer types.
that person is me definitly
I was just wishing, when I wrote that, that I did know someone who did that... purely out of curiosity, I wanted to ask why they (i.e. you) did that? Is it just to make it more obvious that it's supposed to be a positive number instead of a negative one?
i think i expressed my thought incorrectly (or misinterpreted your message) i meant i'm the person who would expect overloaded unary 'operator+' to be out there it's natural that it does nothing (i.e. returns unmodified argument) -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/05/2010 03:40 PM, DE wrote:
I was just wishing, when I wrote that, that I did know someone who did that... purely out of curiosity, I wanted to ask why they (i.e. you) did that? Is it just to make it more obvious that it's supposed to be a positive number instead of a negative one?
i think i expressed my thought incorrectly (or misinterpreted your message) i meant i'm the person who would expect overloaded unary 'operator+' to be out there it's natural that it does nothing (i.e. returns unmodified argument)
Darn, and here I thought I'd finally get that burning question answered. ;-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvh3D8ACgkQp9x9jeZ9/wR5UQCdFETzpD8uB44cXGPpjvyVoR5f /LYAnjRyOq4G4EukPJ7CGilfFhdsj3mN =zMCT -----END PGP SIGNATURE-----

I sometimes like to use unary plus purely for aesthetic reasons. That is, the following: coordinates.push_back(new Vector(-w,-h)); coordinates.push_back(new Vector(+w,-h)); coordinates.push_back(new Vector(+w,+h)); coordinates.push_back(new Vector(-w,+h)); ..looks nicer to me than: coordinates.push_back(new Vector(-w,-h)); coordinates.push_back(new Vector(w,-h)); coordinates.push_back(new Vector(w,h)); coordinates.push_back(new Vector(-w,h)); Of course, I could (should?) always use whitespace... Chad Nelson wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/05/2010 01:37 PM, DE wrote:
Um, because that operator is used for i + j and returns the sum, right? Did I miss something? I suspect you (Robert) might be looking at the unary + operator... Doh! So I was. I didn't even look at the argument list when I saw it because I've never overloaded the unary +! I don't know anyone who does, but I assume that someone out there, someone will, and would be irritated if it didn't work the same as the built in integer types. that person is me definitly
I was just wishing, when I wrote that, that I did know someone who did that... purely out of curiosity, I wanted to ask why they (i.e. you) did that? Is it just to make it more obvious that it's supposed to be a positive number instead of a negative one? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAkvhxIgACgkQp9x9jeZ9/wQHwQCeNNN6/duASbCfwGiBdGH3vsvE 4doAn2yISlLUBsNXWqvdC7BoPRlznnTJ =k7dT -----END PGP SIGNATURE----- _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/08/2010 08:42 PM, Daniel F. wrote:
I sometimes like to use unary plus purely for aesthetic reasons. [...]
I suspected that would be the reason for it. I couldn't think of anything else it would be useful for.
Of course, I could (should?) always use whitespace...
Could, yes. Should? That's a matter of opinion. The example you gave seems perfectly legitimate to me. Thanks for satisfying my curiosity. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvmB+4ACgkQp9x9jeZ9/wS6JACg554K+kgVswMnxps7YfpHhu3G BwkAnRlTQy3aloWNk9kgatarViV3L9BR =iI6Z -----END PGP SIGNATURE-----

On 8 May 2010 20:55, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
I suspected that would be the reason for it. I couldn't think of anything else it would be useful for.
I've also seen it used to induce integral promotion, and thus affect overload selection. For example: uint8_t x = 32; std::cout << x << +x << "\n";

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/08/2010 09:27 PM, Scott McMurray wrote:
I suspected that would be the reason for it. I couldn't think of anything else it would be useful for.
I've also seen it used to induce integral promotion, and thus affect overload selection. [...]
I hadn't thought of that. Thanks for the info. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvmEkoACgkQp9x9jeZ9/wR1/QCgrVkVO1oIr0NlK0GqbbHpk9+r OQwAn0X9TKP69NH0UIf4VRIehLjBgw3e =mX1s -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 02:23 PM, Stewart, Robert wrote:
The integer member function template assignment operator could benefit from the advice in <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>. There may well be other member functions that should be changed as well.
I read it when you first mentioned it (though not in detail), but I'm deferring everything related to that until I determine whether copy-on-write is going to be used in the final version of the library. If it is, then passing by value is cheap in all cases, and is probably best; if not, then it might be better to leave most functions using const references instead, because I'm not convinced that the compiler will have a chance to optimize the copies away in most cases.
If the compiler elides the argument copying, then the COW logic won't be invoked. It's a win with or without COW.
That could well be, but I'll need to prove it to myself before I use that, and I haven't had the time to do so (and probably won't in the next few days at least, there's a lot of restructuring to do on it). [...]
The "not recommended, inefficient" comment for postincrement and postdecrement sounds too harsh. [...]
Not as harsh as not implementing them at all, which is what n1692 recommended. I prefer to implement all of the operators, and leave the decision to the person using the library, with a warning so that he knows to think before using them.
I think part of what you elided was a suggestion that information regarding the inefficiency be put where you can give it fair treatment, not in a terse, somewhat misleading docstring. [...]
Perhaps I misunderstood your recommendation. But I didn't have any more to say on the subject (I assume that anyone who doesn't know why postincrement/postdecrement would be less efficient than their pre- cousins and saw the warning would look it up), and the docstring is the only thing people will see unless they specifically look at the documentation for that function, so I believe it's better to leave it there.
sqr() means, I suppose, square, since you have sqrt(), too. Why not spell it out and remove doubt?
I had a lot of functions, including both of those, spelled out in earlier iterations of the library. I changed them to match the conventions of similar functions in the C and C++ libraries, on the assumption that people would find them easier to remember that way.
What does sqr() do?
sqr's a number, of course. ;-) Anyone familiar with sqrt(double) in the standard library, or sqrt in XInt, should find it to be intuitive naming. I don't expect that it will often need to be used directly anyway.
If you need to parse out the characters that are actually part of a number, like strtol, the stream functions will do that. At least for base 8, 10, and 16 numbers, which I expect will be the main ones that people will use anyway.
I'd prefer to have both forms. That is, if I call the overload which takes a non-const reference to an iterator or size_t, I can determine where the parsing left off and not get an exception. If I assume everything should parse, I'd use the current overload.
Noted. Easy enough to do, I'll just move the code from operator>> and expand on it.
An overload for char const * would be appropriate so as to avoid forcing the creation of a std::string when not already available.
I was under the impression that a char* would be efficiently converted to a const std::string& when needed. If it's less efficient than I was led to believe, then I'll certainly add an overload.
std::string construction from a char * implies free store allocation and copying.
So there isn't any compiler magic that automatically re-uses the existing allocation and just acts as a wrapper around it, for cases like that? How disappointing. Easy enough to add that overload then.
It looks as if you haven't taken advantage of building some of the relational operators on the others. For example, >= is !<. That is, many of the operators should be inlined and only a few need to be implemented.
I'm not sure I see your point. They all consist of a single function call and an int comparison, so the compiler will probably inline them regardless.
I didn't see the implementation of those, so I assumed that they were declarations of non-inlined functions.
I believe they are, but I also believe that the compiler is smart enough to change them to inlined functions. It wouldn't be any major difficulty to make that explicit though.
Nevertheless, this is another case of only having to worry about the implementation of a core set of functions and leave the others in terms of those.
bool operator==(const integer &num1, const integer &num2) { return compare(num1, num2)==0; } bool operator!=(const integer& num1, const integer& num2) { return compare(num1, num2)!=0; } bool operator<(const integer& num1, const integer& num2) { return compare(num1, num2)<0; } bool operator>(const integer& num1, const integer& num2) { return compare(num1, num2)>0; } bool operator<=(const integer& num1, const integer& num2) { return compare(num1, num2)<=0; } bool operator>=(const integer& num1, const integer& num2) { return compare(num1, num2)>=0; } I think you can see the appeal of doing it that way. :-) I might be missing a trick there, but I don't think so... compare returns as soon as it can tell what the answer is; it only has to pursue it to the bitter end when the arguments are equal down to the lowest digit_t. I don't think dedicated functions for each operator could be made any more efficient.
s/template function/function template/
Where do you see them? grep doesn't find the string "template function" anywhere in the source, headers, or documentation.
Search case insensitively. I think it was "Template function" actually.
Ah, found them.
And out of curiosity, do they have different meanings that I'm not aware of, or is this just the commonly-used phrasing?
The correct terminology is "function template" and "class template." IOW, they are templates for generating functions or classes, they are not functions or classes.
Good enough. Though that's a distinction that I'll never be able to remember, so forgive any conversational lapses.
Commentary, like "efficiently" in the to() docstring, should be left for broader library documentation.
Why? It's far more efficient than the method that would almost certainly otherwise be used, which is to stream it out and stream it back to the new type, and I wanted to make that clear. I'm also not sure what broader library documentation you're talking about.
First, I'm assuming that Doxygen generated documentation will be for reference and not for tutorial, rationale, etc. content. That is the "broader library documentation" to which I refer.
That seems like an arbitrary distinction.
Second, when describing what a function does, the word "efficiently" isn't helpful. If you prefer, you can discuss the efficiency aspects in the rest of the docstring (not part of the brief line).
As with the postincrement example, I didn't have anything further to say on the subject -- certainly nothing requiring even a full sentence -- and "efficiently" serves as good shorthand for "more efficiently than other commonly-used methods". It also tells the casual browser the purpose for its existence, so he's more likely to use it for such conversions than automatically fall back on something like lexical_cast.
exceptions::too_big sounds like std::range_error to me.
The wording on std::range_error, in Josuttis' "The C++ Standard Library", is [...]
The name fits nicely, even if the description suggests something slightly different. Arguably, your internal computation determined that the value exceeded the range of the target type, so the exception type is fitting.
In the end, there's no harm in having your own type, given that it does derive from range_error. It allows calling code to be more specific if warranted.
That, and the self-imposed constraint that the library only throw exceptions that are declared in the boost::xint::exception namespace. (Why? Because it seems discordant to me to have a library that only *almost* always throws exceptions from a particular namespace, and it was almost no additional work to make it fit my sense of rightness. In other words, because I can. ;-) ) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvguTIACgkQp9x9jeZ9/wRPgQCgkKZE/XGpZ+E9HO0X8I83l/Tm 3VkAn1Rzh5Nup7l/k7ORSXWDF17T5Nug =22Ix -----END PGP SIGNATURE-----

On 05/04/2010 05:17 PM, Chad Nelson wrote:
On 05/04/2010 02:23 PM, Stewart, Robert wrote: [...]
What does sqr() do?
sqr's a number, of course. ;-) Anyone familiar with sqrt(double) in the standard library, or sqrt in XInt, should find it to be intuitive naming. I don't expect that it will often need to be used directly anyway.
FWIW, I prefer "square", but I know of at least one library that chose to use sqr (and given my opinions of this library, I wouldn't consider that a point in your favor ;) My rationale: I've always considered the "r" in "sqrt" to be the "r" in "root", which doesn't jive well with the "r" in "sqr". And "square" is still plenty short. Hardly the tallest nail, though ;) [...]
Nevertheless, this is another case of only having to worry about the implementation of a core set of functions and leave the others in terms of those.
bool operator==(const integer&num1, const integer&num2) { return compare(num1, num2)==0; } bool operator!=(const integer& num1, const integer& num2) { return compare(num1, num2)!=0; } bool operator<(const integer& num1, const integer& num2) { return compare(num1, num2)<0; } bool operator>(const integer& num1, const integer& num2) { return compare(num1, num2)>0; } bool operator<=(const integer& num1, const integer& num2) { return compare(num1, num2)<=0; } bool operator>=(const integer& num1, const integer& num2) { return compare(num1, num2)>=0; }
I think you can see the appeal of doing it that way. :-) I might be missing a trick there, but I don't think so... compare returns as soon as it can tell what the answer is; it only has to pursue it to the bitter end when the arguments are equal down to the lowest digit_t. I don't think dedicated functions for each operator could be made any more efficient.
I don't have a problem with this, other than (generally speaking) operator==/operator!= often have a more efficient implementation than through compare. For example, if lengths of num1 and num2 are equal, it might be better (heuristically) to start comparing from the least significant chunk rather than the most significant chunk, since it might be expected for less significant chunks to have less correlation than more significant chunks. In the end, the order you compare the chunks in operator==/operator!= probably doesn't make a difference. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 11:50 PM, Jeffrey Lee Hellrung, Jr. wrote:
[...]
What does sqr() do?
sqr's a number, of course. ;-) Anyone familiar with sqrt(double) in the standard library, or sqrt in XInt, should find it to be intuitive naming. I don't expect that it will often need to be used directly anyway.
FWIW, I prefer "square", but I know of at least one library that chose to use sqr (and given my opinions of this library, I wouldn't consider that a point in your favor ;)
Oops, I'd better change it then. ;-)
My rationale: I've always considered the "r" in "sqrt" to be the "r" in "root", which doesn't jive well with the "r" in "sqr". And "square" is still plenty short.
Yes, the need for that 'r' is an annoying inconsistency.
Hardly the tallest nail, though ;)
True enough. [...]
bool operator>=(const integer& num1, const integer& num2) { return compare(num1, num2)>=0; }
I think you can see the appeal of doing it that way. :-) I might be missing a trick there, but I don't think so... compare returns as soon as it can tell what the answer is; it only has to pursue it to the bitter end when the arguments are equal down to the lowest digit_t. I don't think dedicated functions for each operator could be made any more efficient.
I don't have a problem with this, other than (generally speaking) operator==/operator!= often have a more efficient implementation than through compare. For example, if lengths of num1 and num2 are equal, it might be better (heuristically) to start comparing from the least significant chunk rather than the most significant chunk, since it might be expected for less significant chunks to have less correlation than more significant chunks.
Yes, that might be slightly better. Easy enough to add; I've put it on the to-do list.
In the end, the order you compare the chunks in operator==/operator!= probably doesn't make a difference.
Not by any noticeable amount, but if the cost in programmer-time is minimal and there's no other reason to avoid it, I'd prefer to take all the efficiency I can get. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvhdCcACgkQp9x9jeZ9/wTiYwCghvlTJB4rVFqU+G0DaJszBlPT MR8AnRhAKGLtjB6Fmo3v0GyPLCS3MNH/ =qg/7 -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/04/2010 02:23 PM, Stewart, Robert wrote:
The "not recommended, inefficient" comment for postincrement and postdecrement sounds too harsh. [...] [snip] Perhaps I misunderstood your recommendation. But I didn't have any more to say on the subject (I assume that anyone who doesn't know why postincrement/postdecrement would be less efficient than their pre- cousins and saw the warning would look it up), and the docstring is the only thing people will see unless they specifically look at the documentation for that function, so I believe it's better to leave it there.
I expected that you'd discuss the actual overhead of the post- operators so users could make an informed decision. Yes, we all know that the post- operators are less efficient, but in your case, because of the memory allocation and large amount of data that may be copied, it can be worse than one might assume, because of the work your class must do.
sqr() means, I suppose, square, since you have sqrt(), too. Why not spell it out and remove doubt? [snip] What does sqr() do?
sqr's a number, of course. ;-) Anyone familiar with sqrt(double) in the standard library, or sqrt in XInt, should find it to be intuitive naming. I don't expect that it will often need to be used directly anyway.
I still don't understand. Is "sqr" an alternative spelling of "sqrt" or does it mean "square?" I know of sqrt(), but I've never seen sqr() before, so your assertion is false. I found no manpage for it and a cursory search of the Internet turned up nothing on it.
std::string construction from a char * implies free store allocation and copying.
So there isn't any compiler magic that automatically re-uses the existing allocation and just acts as a wrapper around it, for cases like that? How disappointing. Easy enough to add that overload then.
A string class other than std::string could be designed to allocate memory or just point to external memory, according to how it is constructed, but that's not how std::string works.
Nevertheless, this is another case of only having to worry about the implementation of a core set of functions and leave the others in terms of those.
bool operator==(const integer &num1, const integer &num2) { return compare(num1, num2)==0; } bool operator!=(const integer& num1, const integer& num2) { return compare(num1, num2)!=0; } bool operator<(const integer& num1, const integer& num2) { return compare(num1, num2)<0; } bool operator>(const integer& num1, const integer& num2) { return compare(num1, num2)>0; } bool operator<=(const integer& num1, const integer& num2) { return compare(num1, num2)<=0; } bool operator>=(const integer& num1, const integer& num2) { return compare(num1, num2)>=0; }
I think you can see the appeal of doing it that way. :-) I might be missing a trick there, but I don't think so... compare returns as soon as it can tell what the answer is; it only has to pursue it to the bitter end when the arguments are equal down to the lowest digit_t. I don't think dedicated functions for each operator could be made any more efficient.
Those are trivial, and all based upon a single function, so you do get the reuse to which I referred. However, there is an inherent inefficiency here, though it may be miniscule relative to the comparison code. A compare() function must return one of three values: less than zero, zero, or greater than zero. That implies additional logic that isn't necessary when computing <, ==, etc. (Splitting those apart means duplicating portions of the logic in compare(), of course.) BTW, should you implement compare() using memcmp()? I would expect that function to be optimal as it is usually implemented in assembler and takes great advantage of platform characteristics.
Second, when describing what a function does, the word "efficiently" isn't helpful. If you prefer, you can discuss the efficiency aspects in the rest of the docstring (not part of the brief line).
As with the postincrement example, I didn't have anything further to say on the subject -- certainly nothing requiring even a full sentence -- and "efficiently" serves as good shorthand for "more efficiently than other commonly-used methods". It also tells the casual browser the purpose for its existence, so he's more likely to use it for such conversions than automatically fall back on something like lexical_cast.
I contend that "efficiently" is meaningless then. It's a QoI detail, your textual claim has no effect on the code, and it's not quantifiable. It certainly doesn't tell me that one operator is to be preferred over another because the one is described as "efficient" and the other isn't.
exceptions::too_big sounds like std::range_error to me. [snip] In the end, there's no harm in having your own type, given that it does derive from range_error. It allows calling code to be more specific if warranted.
That, and the self-imposed constraint that the library only throw exceptions that are declared in the boost::xint::exception namespace.
(Why? Because it seems discordant to me to have a library that only *almost* always throws exceptions from a particular namespace, and it was almost no additional work to make it fit my sense of rightness. In other words, because I can. ;-) )
That's a nice rationale. Be sure to put it in your docs (assuming it isn't). _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/05/2010 07:56 AM, Stewart, Robert wrote:
The "not recommended, inefficient" comment for postincrement and postdecrement sounds too harsh. [...] [snip] Perhaps I misunderstood your recommendation. But I didn't have any more to say on the subject (I assume that anyone who doesn't know why postincrement/postdecrement would be less efficient than their pre- cousins and saw the warning would look it up), and the docstring is the only thing people will see unless they specifically look at the documentation for that function, so I believe it's better to leave it there.
I expected that you'd discuss the actual overhead of the post- operators so users could make an informed decision. Yes, we all know that the post- operators are less efficient, but in your case, because of the memory allocation and large amount of data that may be copied, it can be worse than one might assume, because of the work your class must do.
It seems obvious to me, but I may well be too close to it to see the problem. I'll add some further information.
sqr() means, I suppose, square, since you have sqrt(), too. Why not spell it out and remove doubt? [snip] What does sqr() do?
sqr's a number, of course. ;-) Anyone familiar with sqrt(double) in the standard library, or sqrt in XInt, should find it to be intuitive naming. I don't expect that it will often need to be used directly anyway.
I still don't understand. Is "sqr" an alternative spelling of "sqrt" or does it mean "square?" I know of sqrt(), but I've never seen sqr() before, so your assertion is false. I found no manpage for it and a cursory search of the Internet turned up nothing on it.
It's not needed in the C/C++ library, since it's just as fast to multiply the numbers together when using single-precision integers. I used that name to fit in with the style of the other libraries. But it doesn't matter now; I've had multiple recommendations to change it, so I will. [...]
bool operator>=(const integer& num1, const integer& num2) { return compare(num1, num2)>=0; }
I think you can see the appeal of doing it that way. :-) I might be missing a trick there, but I don't think so... compare returns as soon as it can tell what the answer is; it only has to pursue it to the bitter end when the arguments are equal down to the lowest digit_t. I don't think dedicated functions for each operator could be made any more efficient.
Those are trivial, and all based upon a single function, so you do get the reuse to which I referred. However, there is an inherent inefficiency here, though it may be miniscule relative to the comparison code. A compare() function must return one of three values: less than zero, zero, or greater than zero. That implies additional logic that isn't necessary when computing <, ==, etc. (Splitting those apart means duplicating portions of the logic in compare(), of course.)
It's quite minuscule. I'm no CPU hardware expert, but my educated guess would be two additional clock cycles per comparison at most. I'll take that cost over the cost of duplicating the logic in multiple functions, especially as it's not trivial.
BTW, should you implement compare() using memcmp()? I would expect that function to be optimal as it is usually implemented in assembler and takes great advantage of platform characteristics.
Unfortunately, memcmp works on bytes, not digit_ts. Since the digit_t type is presumably more than one byte, it would only work correctly on big-endian systems.
Second, when describing what a function does, the word "efficiently" isn't helpful. If you prefer, you can discuss the efficiency aspects in the rest of the docstring (not part of the brief line).
As with the postincrement example, I didn't have anything further to say on the subject -- certainly nothing requiring even a full sentence -- and "efficiently" serves as good shorthand for "more efficiently than other commonly-used methods". It also tells the casual browser the purpose for its existence, so he's more likely to use it for such conversions than automatically fall back on something like lexical_cast.
I contend that "efficiently" is meaningless then. It's a QoI detail, your textual claim has no effect on the code, and it's not quantifiable. It certainly doesn't tell me that one operator is to be preferred over another because the one is described as "efficient" and the other isn't.
I disagree, but again, I may be too close to it to see the problem. I'll add a more expansive explanation.
exceptions::too_big sounds like std::range_error to me. [snip] In the end, there's no harm in having your own type, given that it does derive from range_error. It allows calling code to be more specific if warranted.
That, and the self-imposed constraint that the library only throw exceptions that are declared in the boost::xint::exception namespace.
(Why? Because it seems discordant to me to have a library that only *almost* always throws exceptions from a particular namespace, and it was almost no additional work to make it fit my sense of rightness. In other words, because I can. ;-) )
That's a nice rationale. Be sure to put it in your docs (assuming it isn't).
It isn't, yet. I didn't think it was something that required justification. But it's easy enough to add. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvhfBgACgkQp9x9jeZ9/wREDACfXf0Z5wUtbUcEuzOH7FrHnyhD yWoAoMjMYQ44klKza0wOyHpnhSY2JSsT =6WZJ -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/05/2010 07:56 AM, Stewart, Robert wrote:
However, there is an inherent inefficiency here, though it may be miniscule relative to the comparison code. A compare() function must return one of three values: less than zero, zero, or greater than zero. That implies additional logic that isn't necessary when computing <, ==, etc. (Splitting those apart means duplicating portions of the logic in compare(), of course.)
It's quite minuscule. I'm no CPU hardware expert, but my educated guess would be two additional clock cycles per comparison at most. I'll take that cost over the cost of duplicating the logic in multiple functions, especially as it's not trivial.
I wasn't referring to the comparisons in the operator functions, but rather to the logic in compare() that must produce one of three results; I can't tell if we're talking about the same thing. When implementing the operators directly, there are shortcuts in the logic you can't take in compare(): // untested, written in e-mail editor bool operator ==(base_integer const & _rhs) const { if (_is_zero() != _rhs._is_zero() || _get_negative() != _rhs._get_negative()) { return false; } size_t const length(_get_length()); if (length != _rhs._get_length()) { return false; } detail::digit_t * start(_get_digits()); detail::digit_t * it(start + length); detail::digit_t * rhs_it(_rhs._get_digits() + length); while (it > start) { if (*(--it) != *(--rhs_it)) { return false; } } return true; } That function is simpler than compare() plus a check for zero, so it could prove faster due to fewer branches and comparisons. Is it measurably faster in any meaningful use case? Perhaps. You can reuse some of the algorithm by supplying a predicate and default result so multiple operators -- and compare() -- could use the same comparison loop. (The early returns probably can't be reused appropriately.) _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/05/2010 11:01 AM, Stewart, Robert wrote:
It's quite minuscule. I'm no CPU hardware expert, but my educated guess would be two additional clock cycles per comparison at most. I'll take that cost over the cost of duplicating the logic in multiple functions, especially as it's not trivial.
I wasn't referring to the comparisons in the operator functions, but rather to the logic in compare() that must produce one of three results; I can't tell if we're talking about the same thing.
That's what I was talking about too, and why I estimated that it added two clock cycles, instead of the single one that is all the comparison alone would warrant.
When implementing the operators directly, there are shortcuts in the logic you can't take in compare(): [...]
I appreciate that, but I don't consider the extremely small time savings to be worth the duplication of code, with all the costs that entails, such as the increased chance that a change that should go in both would only make it into one of them, and the extra tests required to ensure full coverage. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvhww0ACgkQp9x9jeZ9/wQBsQCgwqYpkMvaylVeuwAr6dc2BeWG uo8An2qml14Kav/sYNlkWnZQJMV0nyKz =MD/p -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/04/2010 02:23 PM, Stewart, Robert wrote:
It looks as if you haven't taken advantage of building some of the relational operators on the others. For example, >= is !<. That is, many of the operators should be inlined and only a few need to be implemented.
I'm not sure I see your point. They all consist of a single function call and an int comparison, so the compiler will probably inline them regardless.
I didn't see the implementation of those, so I assumed that they were declarations of non-inlined functions.
I believe they are, but I also believe that the compiler is smart enough to change them to inlined functions. It wouldn't be any major difficulty to make that explicit though.
bool operator==(const integer &num1, const integer &num2) { return compare(num1, num2)==0; } bool operator!=(const integer& num1, const integer& num2) { return compare(num1, num2)!=0; } bool operator<(const integer& num1, const integer& num2) { return compare(num1, num2)<0; } bool operator>(const integer& num1, const integer& num2) { return compare(num1, num2)>0; } bool operator<=(const integer& num1, const integer& num2) { return compare(num1, num2)<=0; } bool operator>=(const integer& num1, const integer& num2) { return compare(num1, num2)>=0; }
Having found the definition of compare() for a previous post, I have now found the definition of those operators. Since they are in a .cpp file, they cannot be inlined. You need to move them to integer.hpp (or integer.ipp, if you prefer) for that. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

AMDG Stewart, Robert wrote:
Having found the definition of compare() for a previous post, I have now found the definition of those operators. Since they are in a .cpp file, they cannot be inlined.
That depends on the compiler and linker. Some compilers can inline them anyway.
You need to move them to integer.hpp (or integer.ipp, if you prefer) for that.
In Christ, Steven Watanabe

Steven Watanabe wrote:
Stewart, Robert wrote:
Having found the definition of compare() for a previous post, I have now found the definition of those operators. Since they are in a .cpp file, they cannot be inlined.
That depends on the compiler and linker. Some compilers can inline them anyway.
Sure, but that's not portable, which is the goal within Boost. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

AMDG Stewart, Robert wrote:
Steven Watanabe wrote:
Stewart, Robert wrote:
Having found the definition of compare() for a previous post, I have now found the definition of those operators. Since they are in a .cpp file, they cannot be inlined.
That depends on the compiler and linker. Some compilers can inline them anyway.
Sure, but that's not portable, which is the goal within Boost.
What do you mean by portable? You have no guarantee that the compiler does it? You don't have any guarantees anyway. The compiler is free to ignore inline. In Christ, Steven Watanabe

Steven Watanabe wrote:
Stewart, Robert wrote:
Steven Watanabe wrote:
Stewart, Robert wrote:
Having found the definition of compare() for a previous post, I have now found the definition of those operators. Since they are in a .cpp file, they cannot be inlined.
That depends on the compiler and linker. Some compilers can inline them anyway.
Sure, but that's not portable, which is the goal within Boost.
What do you mean by portable? You have no guarantee that the compiler does it? You don't have any guarantees anyway. The compiler is free to ignore inline.
Ah, but that's portable behavior by definition. As written, the functions in question would only be inlined by a very few platforms. Marked inline in a header, it is the unlikely compiler that wouldn't inline those functions in an optimized build. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

AMDG Stewart, Robert wrote:
Steven Watanabe wrote:
Stewart, Robert wrote:
Sure, but that's not portable, which is the goal within Boost.
What do you mean by portable? You have no guarantee that the compiler does it? You don't have any guarantees anyway. The compiler is free to ignore inline.
Ah, but that's portable behavior by definition.
As written, the functions in question would only be inlined by a very few platforms. Marked inline in a header, it is the unlikely compiler that wouldn't inline those functions in an optimized build.
As far as I am concerned, this has nothing to do with portability as a goal for Boost. We're talking about optimizations that don't affect the observable behavior of any program. The compiler is free to do whatever it darn well pleases, regardless of whether you say inline or not. msvc has supported link time code generation for a while, and gcc now has -flto. In Christ, Steven Watanabe

Steven Watanabe wrote:
Stewart, Robert wrote:
Steven Watanabe wrote:
Stewart, Robert wrote:
Sure, but that's not portable, which is the goal within Boost.
What do you mean by portable? You have no guarantee that the compiler does it? You don't have any guarantees anyway. The compiler is free to ignore inline.
Ah, but that's portable behavior by definition.
As written, the functions in question would only be inlined by a very few platforms. Marked inline in a header, it is the unlikely compiler that wouldn't inline those functions in an optimized build.
As far as I am concerned, this has nothing to do with portability as a goal for Boost. We're talking about optimizations that don't affect the observable behavior of any program. The compiler is free to do whatever it darn well pleases, regardless of whether you say inline or not. msvc has supported link time code generation for a while, and gcc now has -flto.
You've dragged this far afield. The original contention was that functions in a .cpp would be inlined. I countered that as not being portable, which is to say that it will only work on select platforms and only when configured to do so. The only way to have any chance of inlining for the widest range of platforms and configurations possible is to put the function definitions in a header and mark them inline if they aren't in the class definition. That won't force any compiler to inline them, but that gives the best chance for it. I hardly think that's controversial. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

AMDG Stewart, Robert wrote:
Steven Watanabe wrote:
As far as I am concerned, this has nothing to do with portability as a goal for Boost. We're talking about optimizations that don't affect the observable behavior of any program. The compiler is free to do whatever it darn well pleases, regardless of whether you say inline or not. msvc has supported link time code generation for a while, and gcc now has -flto.
You've dragged this far afield. The original contention was that functions in a .cpp would be inlined.
And you claimed that they can't be inlined.
I countered that as not being portable, which is to say that it will only work on select platforms and only when configured to do so.
Like all optimizations.
The only way to have any chance of inlining for the widest range of platforms and configurations possible is to put the function definitions in a header and mark them inline if they aren't in the class definition. That won't force any compiler to inline them, but that gives the best chance for it. I hardly think that's controversial.
It's more likely that they'll be inlined, sure. But why do you care? inlining these functions probably won't have much effect on performance. At most you save one function call and one conditional branch. If I really care about differences like this, I'm probably going to be turning on whole program optimization. Further, I highly doubt that we're going to do the micro-optimizations to make it run as fast as possible on less widely used compilers, anyway. In Christ, Steven Watanabe

Steven Watanabe wrote:
Stewart, Robert wrote:
Steven Watanabe wrote:
You've dragged this far afield. The original contention was that functions in a .cpp would be inlined.
And you claimed that they can't be inlined.
I claimed they wouldn't be, because I assumed -O2 or -O3 as the usual sort of optimizations settings, such as offered by Boost out of the box, unless I'm much mistaken.
I countered that as not being portable, which is to say that it will only work on select platforms and only when configured to do so.
Like all optimizations.
True, but putting inlineable function definitions in a header doesn't require any special settings, so it isn't the same.
The only way to have any chance of inlining for the widest range of platforms and configurations possible is to put the function definitions in a header and mark them inline if they aren't in the class definition. That won't force any compiler to inline them, but that gives the best chance for it. I hardly think that's controversial.
It's more likely that they'll be inlined, sure. But why do you care?
Chad was operating under the assumption that those functions would be inlined and they wouldn't be for most library users.
inlining these functions probably won't have much effect on performance.
It is good to develop a new library without inlining any or most functions. That gives the most flexibility to users without imposing frequent recompilation. I assume the use of profiling to show where optimizations are most needed. However, when writing a library, the author cannot foresee all use cases, so avoiding obvious inlining opportunities is typically bad and likely a premature pessimization.
At most you save one function call and one conditional branch.
If that occurs 1,000,000 times, you just might care, depending upon the processor hosting your app.
If I really care about differences like this, I'm probably going to be turning on whole program optimization. Further, I highly doubt that we're going to do the micro-optimizations to make it run as fast as possible on less widely used compilers, anyway.
This has little to do with micro-optimizations for less used compilers. Few people I have worked with make any use of any of the options that would lead to inlining those functions from the .cpp file, and some potential library users don't even have the option, so the suggested change means an easy optimization for all. That's a good reason to consider the change. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 05.05.2010 at 22:03 Stewart, Robert wrote :
Steven Watanabe wrote:
At most you save one function call and one conditional branch.
If that occurs 1,000,000 times, you just might care, depending upon the processor hosting your app.
i bet even if that occurs million times you won't notice the difference do you care your program to run in 999 milliseconds instead of 1 second? -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/05/2010 11:06 AM, Stewart, Robert wrote:
I didn't see the implementation of those, so I assumed that they were declarations of non-inlined functions.
I believe they are, but I also believe that the compiler is smart enough to change them to inlined functions. It wouldn't be any major difficulty to make that explicit though.
[...]
Having found the definition of compare() for a previous post, I have now found the definition of those operators. Since they are in a .cpp file, they cannot be inlined. You need to move them to integer.hpp (or integer.ipp, if you prefer) for that.
I've just read the back-and-forth on the subject. I *did* assume that the compiler was smart enough to inline them anyway, but I've already agreed to mark them inline, which will require putting them in a header file. So there's no need to argue about it. :-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvhw8AACgkQp9x9jeZ9/wQEcwCeJfin1S0C5dgRRkVk066qQA6x UloAoMMCbtJ0CpLhx4LGS+FZTEhWzpcY =s2PQ -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 04/30/2010 06:48 AM, Neal Becker wrote:
It would be good to remind us what this is
The Extended Integer library provides arbitrary-length integers. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkva500ACgkQp9x9jeZ9/wQZzgCgxaRkEXzJaeyHgCkWYjMEUTvy 8LcAnjtbpUIube3pGg0pXTbhpvI49iIA =2bMJ -----END PGP SIGNATURE-----

on 30.04.2010 at 9:35 Chad Nelson wrote :
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault.
This is a major overhaul of the library, taking into account all of the feedback and recommendations provided on the first two:
* The exception-blocking system is gone, replaced by a separate nothrow_integer class.
* There's now a fixed_integer class template as well. yay!
* The test functions now use Boost.Test, and the documentation has been moved to Doxygen. yay!
* Nearly every function received a thorough examination as well; many of them were tweaked, and a few completely replaced.
Please take a look and let me know what you think of the changes. I'm very happy with them.
you did a great job indeed! did you like using doxygen? was it worth it? ahh.. told you! your docs are very neat and i like your style of documenting however there are some additional cool things that you can make with the docs to your taste but you already did a great step in doc writing! i hope at least you enjoied the results i haven't read it all yet so i'll write my thoughts about _the library_ a bit later -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 04/30/2010 03:10 PM, DE wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
you did a great job indeed!
Thanks!
did you like using doxygen? was it worth it? ahh.. told you!
Yes, I was pleasantly surprised at how much easier it was.
your docs are very neat and i like your style of documenting however there are some additional cool things that you can make with the docs to your taste
Oh?
but you already did a great step in doc writing! i hope at least you enjoied the results
They do look very nice, much nicer than the half-done attempts at Doxygen documentation that I've seen before.
i haven't read it all yet so i'll write my thoughts about _the library_ a bit later
I think I see another message with some of them now. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvbTxgACgkQp9x9jeZ9/wRwSgCePbs3+x8Mstln91ktqZ1hM9Yv ZHEAoNAOjkjzUo+aBefoLZXdyVS/n4gb =FQ9h -----END PGP SIGNATURE-----

I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault.
This is a major overhaul of the library, taking into account all of the feedback and recommendations provided on the first two:
* The exception-blocking system is gone, replaced by a separate nothrow_integer class.
* There's now a fixed_integer class template as well.
yay!
* The test functions now use Boost.Test, and the documentation has been moved to Doxygen.
yay!
* Nearly every function received a thorough examination as well; many of them were tweaked, and a few completely replaced.
Please take a look and let me know what you think of the changes. I'm very happy with them.
Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program. And if all the libraries in boost will have compile time options like that it will quickly become unmanageable for distributions. I would suggest that you either make thread safe the default compile behaviour or offer both safe and unsafe classes. Or better make it all a header only library wich i'd think is a good idea considering that it is not likely to bloat a program that much or to be too time consuming to compile.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 03:32 AM, Marius wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program.
I see your point, but I don't consider that a major problem. Most people using the library won't need thread-safe operation; the ones that do can compile it themselves with little effort.
And if all the libraries in boost will have compile time options like that it will quickly become unmanageable for distributions.
That's hardly a problem, since "all the libraries in boost" *don't* have that kind of compile-time option. Though several of them already do... just off the top of my head, Boost.Regex requires a compile-time option to support Unicode characters, and I seem to recall several others.
I would suggest that you either make thread safe the default compile behaviour
That's not really an option, for two reasons: thread-safe behavior is markedly slower, and it has dependencies on Boost.Move (which isn't yet an official Boost library) and Boost.Thread (which, as a compiled library itself, requires linking). The single-thread version is much faster and doesn't require either of those.
or offer both safe and unsafe classes.
Certainly possible, though it would complicate the library.
Or better make it all a header only library wich i'd think is a good idea considering that it is not likely to bloat a program that much or to be too time consuming to compile.
That *would* simplify things a great deal. I've never tried it though... an extra 130K of headers in every source code file that uses the library is a little much, isn't it? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcRkUACgkQp9x9jeZ9/wSiQgCg7HPo0X/1OLTzmMrGB/eyJO8R BEkAoOLTyH2ZxofLBHkJDqt90eOPI6qz =+/nJ -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 5:18 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 03:32 AM, Marius wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program.
I see your point, but I don't consider that a major problem. Most people using the library won't need thread-safe operation; the ones that do can compile it themselves with little effort.
And if all the libraries in boost will have compile time options like that it will quickly become unmanageable for distributions.
That's hardly a problem, since "all the libraries in boost" *don't* have that kind of compile-time option. Though several of them already do... just off the top of my head, Boost.Regex requires a compile-time option to support Unicode characters, and I seem to recall several others.
I would suggest that you either make thread safe the default compile behaviour
That's not really an option, for two reasons: thread-safe behavior is markedly slower, and it has dependencies on Boost.Move (which isn't yet an official Boost library) and Boost.Thread (which, as a compiled library itself, requires linking). The single-thread version is much faster and doesn't require either of those.
or offer both safe and unsafe classes.
Certainly possible, though it would complicate the library.
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not. Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 11:27 AM, vicente.botet wrote:
[...] or offer both safe and unsafe classes.
Certainly possible, though it would complicate the library.
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not.
That would solve the speed problem, but the dependency problem would remain -- the library would have to use Boost.Move and Boost.Thread always. (See the previous message in this thread for my reasons why that isn't desirable.) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcTBgACgkQp9x9jeZ9/wTMugCg0tAno3g8UQdiU9ZisiNgA84U mEYAnRqVLV6HX9DTIBac67xx7xOO75aE =dY0N -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 5:43 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 11:27 AM, vicente.botet wrote:
[...] or offer both safe and unsafe classes.
Certainly possible, though it would complicate the library.
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not.
That would solve the speed problem, but the dependency problem would remain -- the library would have to use Boost.Move and Boost.Thread always. (See the previous message in this thread for my reasons why that isn't desirable.)
I don't think the dependency is a problem. BTW you have not answered yet to another post I did today. "" you forget to say in the documentation that your library needs to be built and included on the user program. Ths is inportant to know for a lot of people. "How do I use it? That's the best part. If you've installed or compiled the Boost library already, all you need to do is add #include <boost/xint/xint.hpp> at the top of your source code file and declare your variable as type boost::xint::integer." "" If your library needs already to be linked, I dont see a problem to link with lib thread also. Another approach is to have two libraries one working with classes that are not thread safe and more efficient and the other thread safe, depending on Boost.Thread and less efficient. Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 01:09 PM, vicente.botet wrote:
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not.
That would solve the speed problem, but the dependency problem would remain -- the library would have to use Boost.Move and Boost.Thread always. (See the previous message in this thread for my reasons why that isn't desirable.)
I don't think the dependency is a problem.
If I were using a library, I'd prefer that it didn't have an unnecessary dependency on another library that would require me to add that other library to my build system (which, at least under Linux, would be necessary), or that would require me to hunt down an unofficial library before I could use it.
BTW you have not answered yet to another post I did today. "" you forget to say in the documentation that your library needs to be built and included on the user program. Ths is inportant to know for a lot of people.
I saw it and noted it. I didn't think it needed a response, especially as there was a suggestion to make XInt a header-only library.
If your library needs already to be linked, I dont see a problem to link with lib thread also.
Another approach is to have two libraries one working with classes that are not thread safe and more efficient and the other thread safe, depending on Boost.Thread and less efficient.
I'm confused... what is the difference between having two separate libraries and having a compile-time option? The compile-time option leads directly to having two separate compiled versions of the library. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcbvMACgkQp9x9jeZ9/wTcSQCgtOPlzKLy+ekweUCLv8OTV611 YMgAn0zhUayioZm35CdkZpfyvQiKhX+M =guQi -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 8:12 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 01:09 PM, vicente.botet wrote:
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not.
That would solve the speed problem, but the dependency problem would remain -- the library would have to use Boost.Move and Boost.Thread always. (See the previous message in this thread for my reasons why that isn't desirable.)
I don't think the dependency is a problem.
If I were using a library, I'd prefer that it didn't have an unnecessary dependency on another library that would require me to add that other library to my build system (which, at least under Linux, would be necessary), or that would require me to hunt down an unofficial library before I could use it.
BTW you have not answered yet to another post I did today. "" you forget to say in the documentation that your library needs to be built and included on the user program. Ths is inportant to know for a lot of people.
I saw it and noted it. I didn't think it needed a response, especially as there was a suggestion to make XInt a header-only library.
I miss this point.
If your library needs already to be linked, I dont see a problem to link with lib thread also.
Another approach is to have two libraries one working with classes that are not thread safe and more efficient and the other thread safe, depending on Boost.Thread and less efficient.
I'm confused... what is the difference between having two separate libraries and having a compile-time option? The compile-time option leads directly to having two separate compiled versions of the library.
You have misunderstood my concern. I mean to have a library xint and a library xint_ts (thread safe), as we have have now signals and signals2. This provides two libraries with different features can can leave on the same executable. User that don't need the xint_ts dont have to link with lib thread. Of course, xint_ts can use anything xint provides, but not the oposit. Just an idea, that solves a lot of issue taking in account the different user expectations. Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 02:52 PM, vicente.botet wrote:
I'm confused... what is the difference between having two separate libraries and having a compile-time option? The compile-time option leads directly to having two separate compiled versions of the library.
You have misunderstood my concern. I mean to have a library xint and a library xint_ts (thread safe), as we have have now signals and signals2. This provides two libraries with different features can can leave on the same executable.
User that don't need the xint_ts dont have to link with lib thread. Of course, xint_ts can use anything xint provides, but not the oposit.
Just an idea, that solves a lot of issue taking in account the different user expectations.
The thread-safe version would be different from the single-thread version in only two tiny pieces of code (one for a shared resource, one that turns off the copy-on-write stuff). Is that enough to really justify a separate library? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcpLAACgkQp9x9jeZ9/wQsiwCdFIcEkpV/gLOBhsE9I+3qynUw uIUAn1fiN8llN/1/UUR8hbMcx0cgls7u =xGwO -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Sunday, May 02, 2010 12:01 AM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 02:52 PM, vicente.botet wrote:
I'm confused... what is the difference between having two separate libraries and having a compile-time option? The compile-time option leads directly to having two separate compiled versions of the library.
You have misunderstood my concern. I mean to have a library xint and a library xint_ts (thread safe), as we have have now signals and signals2. This provides two libraries with different features can can leave on the same executable.
User that don't need the xint_ts dont have to link with lib thread. Of course, xint_ts can use anything xint provides, but not the oposit.
Just an idea, that solves a lot of issue taking in account the different user expectations.
The thread-safe version would be different from the single-thread version in only two tiny pieces of code (one for a shared resource, one that turns off the copy-on-write stuff). Is that enough to really justify a separate library?
Good new, if the differences are minor, you will take advantage from more common code. Well, you can add a template traits class to the xint::integer class that do whatever is differennt between both versions namespace xint { template <typename IntegerThreadingTraits = integer_single_threading_traits> class interger; } class integer will use this trait class whenever there is a specificity. WHat is expected from the IntegerThreadingTraits class is up to you and depend on the differences. Then you can define the class xint_ts::integer in a separated file as #include <boost/xint/integer_multi_threading_traits.hpp> namespace xint_ts { typedef xint::integer<integer_multi_threading_traits> interger; } This file will depend indirectly on Boost.Thread via integer_multi_threading_traits. Let me know if you need more details. Best, Vicente

Chad Nelson wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 01:09 PM, vicente.botet wrote:
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not. That would solve the speed problem, but the dependency problem would remain -- the library would have to use Boost.Move and Boost.Thread always. (See the previous message in this thread for my reasons why that isn't desirable.) I don't think the dependency is a problem.
If I were using a library, I'd prefer that it didn't have an unnecessary dependency on another library that would require me to add that other library to my build system (which, at least under Linux, would be necessary),
Could you clarify? On Linux, the official way is the shared linking, and therefore the client does not need to care what dependencies libxint.so might have -- they will be picked up automatically. - Volodya

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 02:49 AM, Vladimir Prus wrote:
If I were using a library, I'd prefer that it didn't have an unnecessary dependency on another library that would require me to add that other library to my build system (which, at least under Linux, would be necessary),
Could you clarify? On Linux, the official way is the shared linking, and therefore the client does not need to care what dependencies libxint.so might have -- they will be picked up automatically.
I'm not familiar with shared linking. I don't think I've seen it work, because (as an example purely from memory) when I try to use Boost.FileSystem, I have to manually put in instructions for the linker to link to Boost.System as well, or I get linker errors. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdlHwACgkQp9x9jeZ9/wT+bQCgyXJdU2bCpHpCw5ZSP6FuGvaQ 06oAoNnuvYB75QOvHvgg9DHNAV9fUrzZ =gi44 -----END PGP SIGNATURE-----

Chad Nelson wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/02/2010 02:49 AM, Vladimir Prus wrote:
If I were using a library, I'd prefer that it didn't have an unnecessary dependency on another library that would require me to add that other library to my build system (which, at least under Linux, would be necessary), Could you clarify? On Linux, the official way is the shared linking, and therefore the client does not need to care what dependencies libxint.so might have -- they will be picked up automatically.
I'm not familiar with shared linking. I don't think I've seen it work, because (as an example purely from memory) when I try to use Boost.FileSystem, I have to manually put in instructions for the linker to link to Boost.System as well, or I get linker errors.
I think this is either problem with specific library (easy to fix), or you were actually using static linking, or it was Windows (which does not have all the same magic). - Volodya

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 08:37 PM, Vladimir Prus wrote:
I'm not familiar with shared linking. I don't think I've seen it work, because (as an example purely from memory) when I try to use Boost.FileSystem, I have to manually put in instructions for the linker to link to Boost.System as well, or I get linker errors.
I think this is either problem with specific library (easy to fix), or you were actually using static linking, or it was Windows (which does not have all the same magic).
It was definitely under Linux, and definitely not static linking. It could be a problem with the compiled Boost.FileSystem package in the repositories though, I don't know enough about shared linking to rule that out. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkveKPsACgkQp9x9jeZ9/wTWCgCgwxQRIPi1kzhUPWYrPs3VOCSA duEAoJLhInd4pZJzj2LCBmtiG4LndC3u =OozT -----END PGP SIGNATURE-----

vicente.botet wrote:
----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 5:18 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 03:32 AM, Marius wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...] Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program. I see your point, but I don't consider that a major problem. Most people using the library won't need thread-safe operation; the ones that do can compile it themselves with little effort.
And if all the libraries in boost will have compile time options like that it will quickly become unmanageable for distributions. That's hardly a problem, since "all the libraries in boost" *don't* have that kind of compile-time option. Though several of them already do... just off the top of my head, Boost.Regex requires a compile-time option to support Unicode characters, and I seem to recall several others.
I would suggest that you either make thread safe the default compile behaviour That's not really an option, for two reasons: thread-safe behavior is markedly slower, and it has dependencies on Boost.Move (which isn't yet an official Boost library) and Boost.Thread (which, as a compiled library itself, requires linking). The single-thread version is much faster and doesn't require either of those.
or offer both safe and unsafe classes. Certainly possible, though it would complicate the library.
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not.
That does not seem like a great idea. Suppose my application uses a library A that uses library B that uses library C that uses xint -- and library A uses xint classes in its interface. I certainly don't want all those libraries to suddely be templated on threading model -- where a library might not have a single function template in the first place. Also, why is MT version markedly slower? What, exactly, is the shared data that needs to be protected in MT case -- it would seem to me that adding a couple of large integers in one thread is unrelated to multiplying a couple of other interegers in another thread. - Volodya

----- Original Message ----- From: "Vladimir Prus" <ghost@cs.msu.su> To: <boost@lists.boost.org> Sent: Sunday, May 02, 2010 8:55 AM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
vicente.botet wrote:
----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 5:18 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 03:32 AM, Marius wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...] Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program. I see your point, but I don't consider that a major problem. Most people using the library won't need thread-safe operation; the ones that do can compile it themselves with little effort.
And if all the libraries in boost will have compile time options like that it will quickly become unmanageable for distributions. That's hardly a problem, since "all the libraries in boost" *don't* have that kind of compile-time option. Though several of them already do... just off the top of my head, Boost.Regex requires a compile-time option to support Unicode characters, and I seem to recall several others.
I would suggest that you either make thread safe the default compile behaviour That's not really an option, for two reasons: thread-safe behavior is markedly slower, and it has dependencies on Boost.Move (which isn't yet an official Boost library) and Boost.Thread (which, as a compiled library itself, requires linking). The single-thread version is much faster and doesn't require either of those.
or offer both safe and unsafe classes. Certainly possible, though it would complicate the library.
Couldn't you add a template parameter stating the thread model? This parameter can be by default single_threaded, and the user can set it also to multi_threaded. In this way you let the user of each xint::integer to decide if the library must ensure thread safety or not.
That does not seem like a great idea. Suppose my application uses a library A that uses library B that uses library C that uses xint -- and library A uses xint classes in its interface. I certainly don't want all those libraries to suddely be templated on threading model -- where a library might not have a single function template in the first place.
Whell imagine I name the template integet as xint:integer_tmpl, and xint_ts::integer is a typedef of xint:integer_tmpl<>. The the libraries could use xint_ts::integer without adding any template. But yes in general it will be easier if thexint implemented thread safe interger without too much overhead. Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 02:55 AM, Vladimir Prus wrote:
Also, why is MT version markedly slower?
Please see my reply of a few minutes ago to Joel Falcou. I'll run some tests later today to find out exactly what's going on.
What, exactly, is the shared data that needs to be protected in MT case -- it would seem to me that adding a couple of large integers in one thread is unrelated to multiplying a couple of other interegers in another thread.
It is -- so long as none of the integers are direct copies of ones in a different thread which haven't been explicitly made unique. XInt uses copy-on-write in the non-threadsafe mode; that's the major difference between the two. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdld8ACgkQp9x9jeZ9/wR8RQCdG46Y2d9P5ZBELUWki+6TMw0p bqUAnjFHoRXeMTXbKtU6aF8/fST0Zbk7 =HG0j -----END PGP SIGNATURE-----

On 1 May 2010, at 16:18, Chad Nelson wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 03:32 AM, Marius wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program.
I see your point, but I don't consider that a major problem. Most people using the library won't need thread-safe operation; the ones that do can compile it themselves with little effort.
I assume the thread-unsafety comes from some kind of COW-type implementation? std::string in many implementations of standard libraries has a similar problem. I don't know about the internals of your library, but would some kind of 'remove_sharing', which promised to make an xint not share data with any other xint, before I passed it off to another thread, solve the problem? Personally, I often work with multithreaded code nowadays, and would prefer not to have to recompile if possible (remember that most linux distributions package boost, requiring the library is recompiled wouldn't be compatible with such systems.) While this would still require care on the side of users, it would solve the problems I personally have. Some might consider it a horrible hack of course... Chris

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 11:59 AM, Christopher Jefferson wrote:
Hi, i must say that i'm a bit concerned about making thread safety a compile time option especially considering that on unix systems you don't ussually compile the library and ship it with your program.
I see your point, but I don't consider that a major problem. Most people using the library won't need thread-safe operation; the ones that do can compile it themselves with little effort.
I assume the thread-unsafety comes from some kind of COW-type implementation? std::string in many implementations of standard libraries has a similar problem.
That's the largest part of the problem. There's also a random-number resource that can't safely be used by more than one thread at a time, but it's only called by a few easily-identifiable functions.
I don't know about the internals of your library, but would some kind of 'remove_sharing', which promised to make an xint not share data with any other xint, before I passed it off to another thread, solve the problem?
Certainly. There's already such a function there, _make_unique(). As you'd expect from the name, that ensures that the object in question has its own storage. So long as it's always called on any integer when it's passed between threads, there's no danger from multithreaded access. I didn't think that was worth mentioning though. If you think people would use it, I'll document it.
Personally, I often work with multithreaded code nowadays, and would prefer not to have to recompile if possible (remember that most linux distributions package boost, requiring the library is recompiled wouldn't be compatible with such systems.)
I do most of my development under Linux (Ubuntu/Debian). I've found that the packaged versions of Boost are incomplete, so I have to compile Boost myself anyway. I don't remember what was missing, but there was at least one library that I considered pretty commonly used that wasn't included.
While this would still require care on the side of users, it would solve the problems I personally have. Some might consider it a horrible hack of course...
If people don't like it, they can recompile the library with the thread-safe option and not worry about it. :-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcW24ACgkQp9x9jeZ9/wQTyACdH4H083iKPqR6CTSOEVkZE1Lq l8gAoJFQXBz7gcMx8JAMRMsX1/Z97Oox =Igoa -----END PGP SIGNATURE-----

On Saturday 01 May 2010 19:48:50 Chad Nelson wrote:
I do most of my development under Linux (Ubuntu/Debian). I've found that the packaged versions of Boost are incomplete, so I have to compile Boost myself anyway. I don't remember what was missing, but there was at least one library that I considered pretty commonly used that wasn't included.
Now that i think about it you migth have a package named boost-dev or boost- devel in the repository that you need to install. The problem is that distros like ubuntu ship only the compiled binary of libraries by default and leave out the headers to save space. Search for it in synaptic. Sorry if that's not the case.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 03:23 PM, Marius Stoica wrote:
I do most of my development under Linux (Ubuntu/Debian). I've found that the packaged versions of Boost are incomplete, so I have to compile Boost myself anyway. I don't remember what was missing, but there was at least one library that I considered pretty commonly used that wasn't included.
Now that i think about it you migth have a package named boost-dev or boost- devel in the repository that you need to install. The problem is that distros like ubuntu ship only the compiled binary of libraries by default and leave out the headers to save space. Search for it in synaptic. Sorry if that's not the case.
I'm pretty sure I had the development package when I tried that, and it was definitely missing at least one commonly-used library that I needed. Not a big deal, I just compile Boost myself. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvd2gUACgkQp9x9jeZ9/wQVkQCeJ3Xqkvf5OKnbPBBmlpdZQ6VE QhAAoN6/I+8V3niyC/vh8o8kewk9/di0 =/fxl -----END PGP SIGNATURE-----

Which are the operations on xint::integer do you want to make thread safe? _____________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 04:46 PM, vicente.botet wrote:
Which are the operations on xint::integer do you want to make thread safe?
Having an integer in one thread, making a copy of it, and using that copy in a different thread. That's the only operation where the copy-on-write setup is *not* thread-safe, so far as I know. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvd6igACgkQp9x9jeZ9/wScOACdFSPwlKREgHI7aMovlehzUdPf JrEAn0A2WCmgvk9qo6P7o6/qCQnPF+es =a7fl -----END PGP SIGNATURE-----

Could you confirm that this are the only data stored on xint::integer? flag_t flags; data_t *data; What is the meaning of flags static const flag_t flag_negative = 0x01; static const flag_t flag_readonly = 0x02; static const flag_t flag_fixedlength = 0x04; Is the flags field needed when COW is not used? Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 05:21 PM, vicente.botet wrote:
Could you confirm that this are the only data stored on xint::integer?
flag_t flags; data_t *data;
Yes, that's it, at the moment.
What is the meaning of flags static const flag_t flag_negative = 0x01; static const flag_t flag_readonly = 0x02; static const flag_t flag_fixedlength = 0x04;
The first is used (in the 'flags' bitfield) to denote a negative number. The second identifies data_t items that are meant to never be modified (the zero items assigned when new integers are created without specifying a value, for instance). The third is used on fixed_integer types, to tell the base_integer allocation code to use some special handling for them.
Is the flags field needed when COW is not used?
Yes. I don't think any of those three flags are specific to copy-on-write, except maybe flag_readonly (which prevents the code from writing to a shared zero, for example). - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkveBAAACgkQp9x9jeZ9/wSSsgCfWuopvH9tE0AICOF6mxsK3+Om l4wAnj2xzCEyZtgQfXGsPPBnydbSVpPg =CR7U -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 1:00 AM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/02/2010 05:21 PM, vicente.botet wrote:
Could you confirm that this are the only data stored on xint::integer?
flag_t flags; data_t *data;
Yes, that's it, at the moment.
What is the meaning of flags static const flag_t flag_negative = 0x01; static const flag_t flag_readonly = 0x02; static const flag_t flag_fixedlength = 0x04;
The first is used (in the 'flags' bitfield) to denote a negative number. The second identifies data_t items that are meant to never be modified (the zero items assigned when new integers are created without specifying a value, for instance). The third is used on fixed_integer types, to tell the base_integer allocation code to use some special handling for them.
Is the flags field needed when COW is not used?
Yes. I don't think any of those three flags are specific to copy-on-write, except maybe flag_readonly (which prevents the code from writing to a shared zero, for example).
I don't understand why any of these informations is not stored on data_t. In addition no information must be stored on base integer that concerns fixed_integer. This is a bad design option, IMHO. Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 01:28 AM, vicente.botet wrote:
What is the meaning of flags static const flag_t flag_negative = 0x01; static const flag_t flag_readonly = 0x02; static const flag_t flag_fixedlength = 0x04;
The first is used (in the 'flags' bitfield) to denote a negative number. The second identifies data_t items that are meant to never be modified (the zero items assigned when new integers are created without specifying a value, for instance). The third is used on fixed_integer types, to tell the base_integer allocation code to use some special handling for them. [...]
I don't understand why any of these informations is not stored on data_t.
flag_negative isn't stored in data_t because if it were, I'd have to make a deep copy of every number when I only want to make it negative for a temporary calculation. flag_fixedlength isn't stored in data_t because that would defeat the purpose of it, which is to identify a fixed_integer to the allocation functions when no data_t has been allocated for it yet. flag_readonly isn't stored in data_t because I'd have to store yet another variable there to handle it, which would be inefficient because I had plenty of room in this really handy flag variable that I already had to have in base_integer anyway.
In addition no information must be stored on base integer that concerns fixed_integer. This is a bad design option, IMHO.
And IMNSHO it isn't. Please give me the courtesy that you would offer any professional that you meet in the physical world, and assume that I have a good reason for every choice I've made until proven otherwise. I know I'm overreacting, and that I shouldn't answer e-mails like this when I'm tired. I do appreciate that I asked you guys to do this, and that you're only trying to make it better. But please also remember that it's a hell of a lot easier to criticize something than to do it yourself. 'Nuf said. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvebbQACgkQp9x9jeZ9/wRmRwCbB/Kf1uajxL7o9XYzXk/yrhXW 5p0An2rvSyj8o2W7P0gjASAptRLW2cnW =QoaL -----END PGP SIGNATURE-----

Chad Nelson-2 wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/03/2010 01:28 AM, vicente.botet wrote:
What is the meaning of flags static const flag_t flag_negative = 0x01; static const flag_t flag_readonly = 0x02; static const flag_t flag_fixedlength = 0x04;
The first is used (in the 'flags' bitfield) to denote a negative number. The second identifies data_t items that are meant to never be modified (the zero items assigned when new integers are created without specifying a value, for instance). The third is used on fixed_integer types, to tell the base_integer allocation code to use some special handling for them. [...]
I don't understand why any of these informations is not stored on data_t.
flag_negative isn't stored in data_t because if it were, I'd have to make a deep copy of every number when I only want to make it negative for a temporary calculation.
Maybe a DSEL could help in this case. Chad Nelson-2 wrote:
flag_fixedlength isn't stored in data_t because that would defeat the purpose of it, which is to identify a fixed_integer to the allocation functions when no data_t has been allocated for it yet.
Maybe this can be stored on fixed interger then? Chad Nelson-2 wrote:
flag_readonly isn't stored in data_t because I'd have to store yet another variable there to handle it, which would be inefficient because I had plenty of room in this really handy flag variable that I already had to have in base_integer anyway.
Maybe a DSEL could help in this case. Could you say more when and how this readonly flag is used? Chad Nelson-2 wrote:
In addition no information must be stored on base integer that concerns fixed_integer. This is a bad design option, IMHO.
And IMNSHO it isn't. Please give me the courtesy that you would offer any professional that you meet in the physical world, and assume that I have a good reason for every choice I've made until proven otherwise.
I'm afraid. I was also tired and should go to sleep before. I should just request you to explain the rationale behind that. Chad Nelson-2 wrote:
I know I'm overreacting, and that I shouldn't answer e-mails like this when I'm tired. I do appreciate that I asked you guys to do this, and that you're only trying to make it better. But please also remember that it's a hell of a lot easier to criticize something than to do it yourself. 'Nuf said.
You are right. It is easier to criticize than to do. I know the critics you have received were together with good constructive suggestions and than both have help to improved your library already. I hope this will be yet the case. Best, Vicente -- View this message in context: http://old.nabble.com/-xint--Third-release-is-ready%2C-requesting-preliminar... Sent from the Boost - Dev mailing list archive at Nabble.com.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 03:39 AM, Vicente Botet Escriba wrote:
flag_negative isn't stored in data_t because if it were, I'd have to make a deep copy of every number when I only want to make it negative for a temporary calculation.
Maybe a DSEL could help in this case.
A domain-specific embedded language? I don't know anything about such programming, but from what I've been able to find, it sounds like a heck of a lot of work for very little benefit.
flag_fixedlength isn't stored in data_t because that would defeat the purpose of it, which is to identify a fixed_integer to the allocation functions when no data_t has been allocated for it yet.
Maybe this can be stored on fixed interger then?
How? fixed_integer doesn't handle its own allocation, it relies on base_integer to do that.
flag_readonly isn't stored in data_t because I'd have to store yet another variable there to handle it, which would be inefficient because I had plenty of room in this really handy flag variable that I already had to have in base_integer anyway.
Maybe a DSEL could help in this case. Could you say more when and how this readonly flag is used?
See base_integer.cpp, function base_integer::_is_fixed.
I'm afraid. I was also tired and should go to sleep before. I should just request you to explain the rationale behind that. [...]
And I should have waited until morning to answer that message. Sorry for going off on you like that. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve8DMACgkQp9x9jeZ9/wT3OACgyo4+sW8JLrEMeuqdL3CYaQ4P oVQAn0dRCqz+6lppJnzcEAySWT0zjhup =upTT -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 5:48 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/03/2010 03:39 AM, Vicente Botet Escriba wrote:
flag_negative isn't stored in data_t because if it were, I'd have to make a deep copy of every number when I only want to make it negative for a temporary calculation.
Maybe a DSEL could help in this case.
A domain-specific embedded language? I don't know anything about such programming, but from what I've been able to find, it sounds like a heck of a lot of work for very little benefit.
The benefit is performances. DSEL is not simple, but for the user of the library this will be a clear benefit.
flag_fixedlength isn't stored in data_t because that would defeat the purpose of it, which is to identify a fixed_integer to the allocation functions when no data_t has been allocated for it yet.
Maybe this can be stored on fixed interger then?
How? fixed_integer doesn't handle its own allocation, it relies on base_integer to do that.
See the mail form Jeffrey. CRTP should help. best, Vicente

On 5/2/2010 10:28 PM, vicente.botet wrote:
In addition no information must be stored on base integer that concerns fixed_integer. This is a bad design option, IMHO.
My "HO" also is that the memory management should be separated from the arithmetic algorithms. Whether the integer is a fixed_integer or not is compile-time information, so I don't think you should be keeping runtime information to mirror that. It sounds like it was your intent for base_integer to provide the implementation of the "core" arithmetic algorithms. I would suggest moving the memory management up (or down, depending on how you view things) to the derived classes. How feasible is that? You can use CRTP to get access to the derived class's members. This probably won't affect the interface or performance any, however, so it's much more an implementation detail than COW. It's still bothering me that you're finding moving to be so much slower than COW :/ We should try to get to the bottom of this. I'll find some time today to examine the code. - Jeff

----- Original Message ----- From: "Jeffrey Lee Hellrung, Jr." <jhellrung@ucla.edu> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 4:54 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
On 5/2/2010 10:28 PM, vicente.botet wrote:
In addition no information must be stored on base integer that concerns fixed_integer. This is a bad design option, IMHO.
My "HO" also is that the memory management should be separated from the arithmetic algorithms. Whether the integer is a fixed_integer or not is compile-time information, so I don't think you should be keeping runtime information to mirror that. It sounds like it was your intent for base_integer to provide the implementation of the "core" arithmetic algorithms. I would suggest moving the memory management up (or down, depending on how you view things) to the derived classes. How feasible is that? You can use CRTP to get access to the derived class's members.
I agree completly. Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 10:54 AM, Jeffrey Lee Hellrung, Jr. wrote:
In addition no information must be stored on base integer that concerns fixed_integer. This is a bad design option, IMHO.
My "HO" also is that the memory management should be separated from the arithmetic algorithms.
For the most part, it is.
Whether the integer is a fixed_integer or not is compile-time information, so I don't think you should be keeping runtime information to mirror that.
It's needed for the memory management code.
It sounds like it was your intent for base_integer to provide the implementation of the "core" arithmetic algorithms.
Close. base_integer handles the memory management; the free functions handle the algorithms. The separation isn't perfect yet though.
I would suggest moving the memory management up (or down, depending on how you view things) to the derived classes. How feasible is that? You can use CRTP to get access to the derived class's members.
It's not really feasible to push it to the derived classes, since it would involve a lot of duplicate code. The memory management is almost completely identical between all of the integer types, so it makes more sense to have it in a base class. However, as I mentioned yesterday, I've found a need to separate the memory management functions from the base class anyway. I plan to move them into an intermediary class, something that inherits from base_integer, and that all the derived classes inherit from.
This probably won't affect the interface or performance any, however, so it's much more an implementation detail than COW. It's still bothering me that you're finding moving to be so much slower than COW :/ We should try to get to the bottom of this. I'll find some time today to examine the code.
I may have identified the reason that it's slower, and as you suspected, it's code that I'd designed while thinking of copy-on-write. I'll experiment with that today. If I can get the move implementation at least as fast as the copy-on-write one, I'll happily remove copy-on-write. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve+wQACgkQp9x9jeZ9/wTa8wCfRtxMQcZIiaBxXYuFo7zHUlRj /ZcAnROOugWfMCNK7s/90ZigWWzTK1i5 =OtSD -----END PGP SIGNATURE-----

on 03.05.2010 at 20:34 Chad Nelson wrote :
On 05/03/2010 10:54 AM, Jeffrey Lee Hellrung, Jr. wrote:
I would suggest moving the memory management up (or down, depending on how you view things) to the derived classes. How feasible is that? You can use CRTP to get access to the derived class's members.
It's not really feasible to push it to the derived classes, since it would involve a lot of duplicate code. The memory management is almost completely identical between all of the integer types, so it makes more sense to have it in a base class.
However, as I mentioned yesterday, I've found a need to separate the memory management functions from the base class anyway. I plan to move them into an intermediary class, something that inherits from base_integer, and that all the derived classes inherit from.
how about making derived classes to call base class' protected methods to initialize the storage? -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "Chad Nelson" <boost@lists.boost.org> Sent: Monday, May 03, 2010 7:19 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 03.05.2010 at 20:34 Chad Nelson wrote :
On 05/03/2010 10:54 AM, Jeffrey Lee Hellrung, Jr. wrote:
I would suggest moving the memory management up (or down, depending on how you view things) to the derived classes. How feasible is that? You can use CRTP to get access to the derived class's members.
It's not really feasible to push it to the derived classes, since it would involve a lot of duplicate code. The memory management is almost completely identical between all of the integer types, so it makes more sense to have it in a base class.
You need to mut the minimal part on the derived part, but don't add to much on the base class.
However, as I mentioned yesterday, I've found a need to separate the memory management functions from the base class anyway. I plan to move them into an intermediary class, something that inherits from base_integer, and that all the derived classes inherit from.
Ths should not solve the problem as both integer and fixed will inherit from this intermediary class.
how about making derived classes to call base class' protected methods to initialize the storage?
This is no necesary. with CRTP the base class can call the Final class. Friend can be added when necessary. Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 01:28 PM, vicente.botet wrote:
It's not really feasible to push it to the derived classes, since it would involve a lot of duplicate code. The memory management is almost completely identical between all of the integer types, so it makes more sense to have it in a base class.
You need to mut the minimal part on the derived part, but don't add to much on the base class.
The usual way to do that is via virtual functions. I've been trying to avoid virtual functions in the base_integer class, for efficiency's sake; the intermediary class mentioned below is intended to solve the problem without need of them.
However, as I mentioned yesterday, I've found a need to separate the memory management functions from the base class anyway. I plan to move them into an intermediary class, something that inherits from base_integer, and that all the derived classes inherit from.
Ths should not solve the problem as both integer and fixed will inherit from this intermediary class.
Of course they will. That's the whole point. What *is* the problem then, that a possibly-templated intermediate class wouldn't solve it? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfDXUACgkQp9x9jeZ9/wR2EgCgjawz2DK6po8sTvr6rGJsLmht OdUAoOWue/qsa8kPNyFmZ8AN9khTGXHD =yGqC -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 7:52 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/03/2010 01:28 PM, vicente.botet wrote:
It's not really feasible to push it to the derived classes, since it would involve a lot of duplicate code. The memory management is almost completely identical between all of the integer types, so it makes more sense to have it in a base class.
You need to mut the minimal part on the derived part, but don't add to much on the base class.
The usual way to do that is via virtual functions. I've been trying to avoid virtual functions in the base_integer class, for efficiency's sake; the intermediary class mentioned below is intended to solve the problem without need of them.
Chad I need to ask you if you knwo the tecnique we are suggesting you, i.e. CRTP Curious Recurring Template Pattern. If this is not the case we could explain you in more detaill how it wan be used to your case.
However, as I mentioned yesterday, I've found a need to separate the memory management functions from the base class anyway. I plan to move them into an intermediary class, something that inherits from base_integer, and that all the derived classes inherit from.
This should not solve the problem as both integer and fixed will inherit from this intermediary class.
Of course they will. That's the whole point. What *is* the problem then, that a possibly-templated intermediate class wouldn't solve it?
That the intermediary class will contain information that is specific to the fixed_integer class. We will see when you implement it. Review this thread to check what was the problem when you said the intermediary class will solve it. Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 03:40 PM, vicente.botet wrote:
You need to mut the minimal part on the derived part, but don't add to much on the base class.
The usual way to do that is via virtual functions. I've been trying to avoid virtual functions in the base_integer class, for efficiency's sake; the intermediary class mentioned below is intended to solve the problem without need of them.
Chad I need to ask you if you knwo the tecnique we are suggesting you, i.e. CRTP Curious Recurring Template Pattern. If this is not the case we could explain you in more detaill how it wan be used to your case.
I've looked into it at least twice in the past, but that's one of those things that I can never seem to remember. Looking it up again... ah, now I remember why I can never seem to remember it: I've never understood the purpose of it in the first place, and never seen it used. Hm... I *think* I see it now. At least, some of the time I think I do. :-) Please check my understanding: you're suggesting that I use functions in base_integer to do the allocation, and have them call other functions in base_integer to do the things that are different between fixed_integer and the variable-length integers. But then override those functions in the fixed_integer classes, not as virtual functions, but using CRTP to call the overridden functions. Am I right? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfTBEACgkQp9x9jeZ9/wQgHwCfQFPPYz3+/74hILL7KTGLpwFx InsAoIxIWXbRtQJ2hZ785KFzEN9k9EEN =0UZg -----END PGP SIGNATURE-----

on 04.05.2010 at 2:20 Chad Nelson wrote :
Hm... I *think* I see it now. At least, some of the time I think I do. :-) Please check my understanding: you're suggesting that I use functions in base_integer to do the allocation, and have them call other functions in base_integer to do the things that are different between fixed_integer and the variable-length integers. But then override those functions in the fixed_integer classes, not as virtual functions, but using CRTP to call the overridden functions. Am I right?
let me try to explain suppose the interface of all your concrete classes (i.e. 'integer', 'nothrow_integer' and 'fixed_integer') is homogeneous that is all classes have identical names for respective members with consistent semantics then each of the classes inherits the base class template<typename type> class base_integer {}; in the following way class integer : public base_integer<integer> {/*...*/}; then you can write template functions for all types in the following manner: template<typename int_type> void foo(const base_integer<int_type>&); template<typename type1, typename type2> void bar(const base_integer<type1>&, const base_integer<type2>&); such functions will handle all types derived from base_integer providing their type as template argument an implementation of such a function can be like this: template<typename type> type negate(const base_integer<type> &a) { const type &instance = *static_cast<type*>(&a); return instance.negated(); } notice that this function returns a concrete type deduced automatically also this function implies that all concrete types have 'negated()' member function (as an example) also the ugly static_cast may be wrapped in a functions: template<typename type> type &get_instance(base_integer<type> &a) { return *static_cast<type*>(&a); } template<typename type> const type &get_instance(const base_integer<type> &a) { return *static_cast<const type*>(&a); } designing a lib this way you have a header with those (CRTP'ed) template stuff while concrete types reside in header and/or cpp file as is convenient for you as well this approach is type safe as long as 'base_integer' parameterized according to the contract please think about it, it is a very powerful design technique, also it may solve a whole lot of troubles now and later i like this theme very much and will happily write more words on this on your demand -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 03:58 AM, DE wrote:
Hm... I *think* I see it now. At least, some of the time I think I do. :-) Please check my understanding: you're suggesting that I use functions in base_integer to do the allocation, and have them call other functions in base_integer to do the things that are different between fixed_integer and the variable-length integers. But then override those functions in the fixed_integer classes, not as virtual functions, but using CRTP to call the overridden functions. Am I right?
let me try to explain
suppose the interface of all your concrete classes (i.e. 'integer', 'nothrow_integer' and 'fixed_integer') is homogeneous that is all classes have identical names for respective members with consistent semantics
Which it should be.
then each of the classes inherits the base class
template<typename type> class base_integer {};
in the following way
class integer : public base_integer<integer> {/*...*/};
Yes, I understand that part.
then you can write template functions for all types in the following manner:
template<typename int_type> void foo(const base_integer<int_type>&); template<typename type1, typename type2> void bar(const base_integer<type1>&, const base_integer<type2>&);
such functions will handle all types derived from base_integer providing their type as template argument
Ah, I see now. It wouldn't matter that there couldn't be a common base class that implements all the common functions, then. I wince slightly at the implied duplication of compiled code, but I think I see how I can minimize it. And of course, people will only get that code for the functions and types that they use.
[...] please think about it, it is a very powerful design technique, also it may solve a whole lot of troubles now and later
Yes, I can see some problems that it would solve already. It may take me a few days of playing with it to figure out the most optimal way to use this, but I like the concept.
i like this theme very much and will happily write more words on this on your demand
Thanks. I think I've got the basic idea, but if I get stuck, I'll ask. :-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvgOj4ACgkQp9x9jeZ9/wTTRACfcHHviBwHSlnmyVWW3OsWCM6S 5Q8AoMO36g5Ks9mn7Y+jlM1avm+vqTG8 =SVyP -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 01:19 PM, DE wrote:
[...] However, as I mentioned yesterday, I've found a need to separate the memory management functions from the base class anyway. I plan to move them into an intermediary class, something that inherits from base_integer, and that all the derived classes inherit from.
how about making derived classes to call base class' protected methods to initialize the storage?
That's what it's doing now, but it doesn't allow for user-defined allocators that way. I'm hoping that the intermediary class will permit allocators while still allowing me to have a concrete base class, so I don't need to make all of the actual operation functions into templates too. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfC9oACgkQp9x9jeZ9/wRLwACgysZSnm1e/4nJWWgvCppaeqr6 wI4AoMdJf06c9PlRuqWKcsN/JzU/JBhZ =ck/h -----END PGP SIGNATURE-----

On Saturday 01 May 2010 18:18:32 Chad Nelson wrote:
That would simplify things a great deal. I've never tried it though... an extra 130K of headers in every source code file that uses the library is a little much, isn't it?
I don't think that's an issue. Most(almost all) of that code is conditionally compiled and the final size of what would end up in a binnary will be very small. Also let me check some of the other libraries in boost. Here in alphabethic order (Afaict all of these are header only) accumulators - 506k algoritm - 305k archive - 395k asio - 1.5MiB assign - 95k bitmap - 488k bind - 177k Also because ubuntu screwed up their boost doesn't mean that all distros will. The default compiled behaviour should be the one that works in all cases not the one that's faster imho.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 02:08 PM, Marius Stoica wrote:
That would simplify things a great deal. I've never tried it though... an extra 130K of headers in every source code file that uses the library is a little much, isn't it?
I don't think that's an issue. Most(almost all) of that code is conditionally compiled and the final size of what would end up in a binnary will be very small.
It's still code that would have to be read and parsed for every compilation unit that includes it. Computers are a lot faster these days than when I learned to program, but that's still enough to make me think twice before doing something like that.
Also let me check some of the other libraries in boost.
Here in alphabethic order (Afaict all of these are header only) accumulators - 506k algoritm - 305k archive - 395k asio - 1.5MiB assign - 95k bitmap - 488k bind - 177k
I've used a few of those, and haven't noticed a major compile-speed problem, which is an argument in your favor.
Also because ubuntu screwed up their boost doesn't mean that all distros will. The default compiled behaviour should be the one that works in all cases not the one that's faster imho.
I'm sorry to say that my opinion differs. If someone is evaluating the library against several others to see which one he wants to use, he's not likely to dig into the documentation to figure out how to get the best speed out of it -- he's going to compare the default configurations. I'd like XInt to still be in the running when he does. Also, multithreaded operation is still fairly uncommon. I'd hate to make everyone pay for something that only a few need, especially when the speed cost is so high (the single-threaded version is *twice* the speed of the multithreaded one). - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvccp4ACgkQp9x9jeZ9/wSyOgCfYjm7OjYCKo4zB+6Rcw1oXynr nCsAn0UmyUcQy9z2JWZyxxXiGbPUsGnF =PP+0 -----END PGP SIGNATURE-----

Also, multithreaded operation is still fairly uncommon. Except not ... I'd hate to make everyone pay for something that only a few need, especially when the speed cost is so high (the single-threaded version is *twice* the speed of the multithreaded one) Then it means you did somethign wrong or the code doesn't lend itself to
Chad Nelson wrote: trivial multithreading ... -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 02:34 PM, joel falcou wrote:
Also, multithreaded operation is still fairly uncommon.
Except not ...
If you're saying that people often write multithreaded programs, then I have to disagree. In my experience, it's rare, and most programmers actively avoid them.
I'd hate to make everyone pay for something that only a few need, especially when the speed cost is so high (the single-threaded version is *twice* the speed of the multithreaded one)
Then it means you did somethign wrong or the code doesn't lend itself to trivial multithreading ...
Would you care to provide some evidence to back up that claim? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcncQACgkQp9x9jeZ9/wRX3wCguVittgVPcXDEY5Twl+bRAMII Bl8An2V4OgxKe04NYo1LHgZGAoYJjGjT =CVcB -----END PGP SIGNATURE-----

Chad Nelson wrote:
If you're saying that people often write multithreaded programs, then I have to disagree. In my experience, it's rare, and most programmers actively avoid them.
Plural of anedocte is not data. In genral, not taking multithreading seriously now is likely to be a problem in the upcoming years.
Then it means you did somethign wrong or the code doesn't lend itself to trivial multithreading ...
Sorry for the tone of that, I wasn't implying anything wrong with yourself, just that this kind of result (multithreaded version being slower) is usually because soemthing don't lend itself to be multithreaded. Do you have this MT code somewhere still, i may have a look if needed.
-- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

On 5/1/2010 11:44 PM, joel falcou wrote:
If you're saying that people often write multithreaded programs, then I have to disagree. In my experience, it's rare, and most programmers actively avoid them. Plural of anedocte is not data. In genral, not taking multithreading seriously now is likely to be a
Chad Nelson wrote: problem in the upcoming years.
Then it means you did somethign wrong or the code doesn't lend itself to trivial multithreading ... Sorry for the tone of that, I wasn't implying anything wrong with yourself, just that this kind of result (multithreaded version being slower) is usually because soemthing don't lend itself to be multithreaded. Do you have this MT code somewhere still, i may have a look if needed.
Chad, what Joel is referring to as "multithreaded" is really "thread-safe" in the context of your library, right? I mean, not that Joel is using incorrect terminology on purpose, but maybe some terms and intents got confused during the discussion. You (Chad) don't actually implement any distributed arithmetic algorithms, right? Why do you need to link to Boost.Thread for the thread-safe version? I'm under the impression the thread-safe version does not use COW, so read-access shouldn't need to be serialized, which puts it at the same level of "thread safety" as the STL containers. I don't see where Boost.Thread fits into this. Do you have static data shared among all xint::integer instances? Regarding COW specifically: I'm guessing COW will be a tough sell, and I'm having a hard time swallowing that COW is 2x faster than (even emulated) move semantics. Is the performance difference strictly from differing numbers of copy operations? Can you identify (i.e., give an example of a real algorithm) where a move-enabled xint::integer produces more copies than a COW-enabled xint::integer? - Jeff

Jeffrey Hellrung wrote:
Chad, what Joel is referring to as "multithreaded" is really "thread-safe" in the context of your library, right? I mean, not that Joel is using incorrect terminology on purpose, but maybe some terms and intents got confused during the discussion. You (Chad) don't actually implement any distributed arithmetic algorithms, right? Oh indeed. Yeah /s/multithreaded/thread-safe/ sorry for the miscommunications there. I thought the second but wrote the first.
Regarding COW specifically: I'm guessing COW will be a tough sell, and I'm having a hard time swallowing that COW is 2x faster than (even emulated) move semantics. Is the performance difference strictly from differing numbers of copy operations? Can you identify (i.e., give an example of a real algorithm) where a move-enabled xint::integer produces more copies than a COW-enabled xint::integer? I'm inerested in there too.
-- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 03:19 AM, Jeffrey Hellrung wrote:
Sorry for the tone of that, I wasn't implying anything wrong with yourself, just that this kind of result (multithreaded version being slower) is usually because soemthing don't lend itself to be multithreaded. Do you have this MT code somewhere still, i may have a look if needed.
Chad, what Joel is referring to as "multithreaded" is really "thread-safe" in the context of your library, right? I mean, not that Joel is using incorrect terminology on purpose, but maybe some terms and intents got confused during the discussion.
Ah, okay. The confusion was probably my fault, I tend to call it "the multithreaded version" when I should call it "the thread-safe version."
You (Chad) don't actually implement any distributed arithmetic algorithms, right?
Right. A few functions, like the random_prime one, could make good use of it, but it should be easy enough for the end-user to implement that if he wants it.
Why do you need to link to Boost.Thread for the thread-safe version? I'm under the impression the thread-safe version does not use COW, so read-access shouldn't need to be serialized, which puts it at the same level of "thread safety" as the STL containers. I don't see where Boost.Thread fits into this. Do you have static data shared among all xint::integer instances?
The only thing that I need Boost.Thread for is serializing access to the random number generator -- I assume that most of the generators provided by Boost.Random can't tolerate being used by multiple threads simultaneously. Boost.Thread is major overkill for that purpose, at least in my opinion, but until Boost.Atomic or something similar is approved, it's the only cross-platform way that I know of to safely serialize access without writing my own code for the purpose.
Regarding COW specifically: I'm guessing COW will be a tough sell,
I keep hearing that, but why? It's an internal detail, one that provides (or at least seems to) a very noticeable speed boost under some circumstances, and is disabled when it can't be safely used. Why would anyone, other than developers doing work on the library (i.e. me), care one way or another that the library uses it?
and I'm having a hard time swallowing that COW is 2x faster than (even emulated) move semantics. Is the performance difference strictly from differing numbers of copy operations? Can you identify (i.e., give an example of a real algorithm) where a move-enabled xint::integer produces more copies than a COW-enabled xint::integer?
Please see my reply from earlier this morning to Joel Falcou. I hadn't thought about it extensively before, but I may be mistaken about most of the source of the slowdown. I'll be testing that further today. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdmmIACgkQp9x9jeZ9/wTt8gCgzbSshmgH0XrFjZpcuHU/4Dk5 3esAoI1vsa2PhvwPoJyz+vocUaeNN8Pu =tUVz -----END PGP SIGNATURE-----

On the documentation you say " Some of these numbers can get huge, making copying an expensive proposition, and even move semantics (at least as emulated by Boost.Move at the time of this writing) aren't as fast" Why do you say on Boost.Move is not as fast as COW? _____________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/

on 02.05.2010 at 20:05 vicente.botet wrote :
On the documentation you say " Some of these numbers can get huge, making copying an expensive proposition, and even move semantics (at least as emulated by Boost.Move at the time of this writing) aren't as fast"
Why do you say on Boost.Move is not as fast as COW?
can i reply? please can i? can i? for example if you make 10 copies of an object cow (or implict sharing) aware objects will share only one representation among all instances, i.e. there is only one allocation, initialization and no copy processes at all in this circumstances move enabled objects would not act as efficient supposing none of that ten copies are temporary you get ten "deep" copies of the first object this involves ten allocations, initializations and costs associated with them so in some circumstances implicit sharing (or cow) will always be faster even if move semantics is implemented otherwise -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "vicente.botet" <boost@lists.boost.org> Sent: Sunday, May 02, 2010 6:42 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 02.05.2010 at 20:05 vicente.botet wrote :
On the documentation you say " Some of these numbers can get huge, making copying an expensive proposition, and even move semantics (at least as emulated by Boost.Move at the time of this writing) aren't as fast"
Why do you say on Boost.Move is not as fast as COW?
can i reply? please can i? can i?
YES, YOU CAN :)
for example if you make 10 copies of an object
cow (or implict sharing) aware objects will share only one representation among all instances, i.e. there is only one allocation, initialization and no copy processes at all
in this circumstances move enabled objects would not act as efficient supposing none of that ten copies are temporary you get ten "deep" copies of the first object this involves ten allocations, initializations and costs associated with them
so in some circumstances implicit sharing (or cow) will always be faster even if move semantics is implemented otherwise
Oh, I see. I was thinking on returning integer types from functions. Best, Vicente

DE wrote:
on 02.05.2010 at 20:05 vicente.botet wrote :
Why do you say on Boost.Move is not as fast as COW?
for example if you make 10 copies of an object
cow (or implict sharing) aware objects will share only one representation among all instances, i.e. there is only one allocation, initialization and no copy processes at all
in this circumstances move enabled objects would not act as efficient supposing none of that ten copies are temporary you get ten "deep" copies of the first object this involves ten allocations, initializations and costs associated with them
PMFJI, but the point of move semantics is to avoid copying, not to make it faster. If Using COW is faster than move semantics, that means there are copies being made. If move semantics were applied with the expectation of reducing copies where they weren't really needed, from rvalues, then perhaps Boost.Move has been misapplied. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 07:34 AM, Stewart, Robert wrote:
PMFJI, but the point of move semantics is to avoid copying, not to make it faster. If Using COW is faster than move semantics, that means there are copies being made. If move semantics were applied with the expectation of reducing copies where they weren't really needed, from rvalues, then perhaps Boost.Move has been misapplied.
I was trying to use it to reduce the copying that is otherwise necessary when returning values (and not using copy-on-write). I think that's its intended use. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve8NsACgkQp9x9jeZ9/wSsjACg2KCjnIAzhMUffib3fV9UbaZu 4yUAn01SZzx7PbfvE+Sf0nMsYNeH0q8I =cq43 -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/03/2010 07:34 AM, Stewart, Robert wrote:
PMFJI, but the point of move semantics is to avoid copying, not to make it faster. If Using COW is faster than move semantics, that means there are copies being made. If move semantics were applied with the expectation of reducing copies where they weren't really needed, from rvalues, then perhaps Boost.Move has been misapplied.
I was trying to use it to reduce the copying that is otherwise necessary when returning values (and not using copy-on-write). I think that's its intended use.
You may be missing an important aspect: reusing temporaries. (N)RVO generally handles efficiently returning values. Where move semantics can really help, though, is in permitting you to use those rvalues for intermediate computations. Refer to the examples given earlier in the thread about moving intermediate results, in a temporary, to the full expression's result. I recall that you did mention multiplication as a case where that couldn't be done because the product would be larger than the multiplicands, though obviously not if either is 1 or 0, so this aspect may not have eluded you. Nevertheless, I wanted to be sure you understood the difference. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 12:55 PM, Stewart, Robert wrote:
I was trying to use it to reduce the copying that is otherwise necessary when returning values (and not using copy-on-write). I think that's its intended use.
You may be missing an important aspect: reusing temporaries. [...] I recall that you did mention multiplication as a case where that couldn't be done because the product would be larger than the multiplicands, though obviously not if either is 1 or 0, so this aspect may not have eluded you. Nevertheless, I wanted to be sure you understood the difference.
I'm starting to. Move semantics are still new to me. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfCwUACgkQp9x9jeZ9/wRw1gCfb5DLCz558Rd5eDRwSdxLJyzJ oDwAn29qUV0TkkBIl16WQdrikl8O41Gf =gc9X -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 12:05 PM, vicente.botet wrote:
On the documentation you say " Some of these numbers can get huge, making copying an expensive proposition, and even move semantics (at least as emulated by Boost.Move at the time of this writing) aren't as fast"
Why do you say on Boost.Move is not as fast as COW?
Because it isn't. I ran some tests when I added Boost.Move to it, and copy-on-write is measurably faster than (emulated) move semantics, by about the same amount that emulated move semantics are faster than not having either. I'm hoping that compiler-supported move semantics will be equal to copy-on-write, but until they're widely available, copy-on-write is better. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdsC8ACgkQp9x9jeZ9/wQSywCgviSixRsdhhm1Z6jR6c0bkAvw 1U8AnAoMV19ANV+w/9xOsFzWfJGnvgwW =zhNO -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Sunday, May 02, 2010 7:02 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/02/2010 12:05 PM, vicente.botet wrote:
On the documentation you say " Some of these numbers can get huge, making copying an expensive proposition, and even move semantics (at least as emulated by Boost.Move at the time of this writing) aren't as fast"
Why do you say on Boost.Move is not as fast as COW?
Because it isn't. I ran some tests when I added Boost.Move to it, and copy-on-write is measurably faster than (emulated) move semantics, by about the same amount that emulated move semantics are faster than not having either. I'm hoping that compiler-supported move semantics will be equal to copy-on-write, but until they're widely available, copy-on-write is better.
Are you saying that given the following functions xint::integer cow(); boost::rv<xint::integer> m(); xint::integer i; i = cow() is faster than i = m() on a single thread environement? If yet, what is the ratio you have measured? Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 01:13 PM, vicente.botet wrote:
Are you saying that given the following functions
xint::integer cow(); boost::rv<xint::integer> m(); xint::integer i;
i = cow() is faster than i = m() on a single thread environement?
That's exactly what I'm saying. Which makes some sense, when you think about it... if the compiler doesn't optimize it perfectly, then it's spending CPU cycles to create the the boost::rv type, only to assign it to another integer and destroy it again. Copy-on-write doesn't need to do any of that.
If yet, what is the ratio you have measured?
It looks like I didn't save the file with the results, but they were something like copy-on-write being 0.3 seconds faster than neither, and move being about 0.15 seconds faster. The test took roughly three seconds at its fastest, if I recall correctly, which would make copy-on-write about 5% faster than move semantics if I've got my sums correct. (The ratio could vary depending on the size of the numbers used though. Larger numbers *should* produce larger savings, since copying them would be more expensive. Though the library would also spend more time within the functions processing each number, so I'm not certain about that.) I'll have to recreate that test code anyway, in order to see how the random number locking affected the speed, so I'll have more detailed results to post later today. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdu+YACgkQp9x9jeZ9/wRiPACg73Mc9wp3Ldnc8cIuwURpFevd mZ8AniHgHr1WH1PXYtb1dL0XZK6j1xoh =uioo -----END PGP SIGNATURE-----

On May 2, 2010, at 11:29 AM, Chad Nelson wrote:
\The only thing that I need Boost.Thread for is serializing access to the random number generator -- I assume that most of the generators provided by Boost.Random can't tolerate being used by multiple threads simultaneously.
Boost.Thread is major overkill for that purpose, at least in my opinion, but until Boost.Atomic or something similar is approved, it's the only cross-platform way that I know of to safely serialize access without writing my own code for the purpose.
I believe much of Boost.Thread can be used header-only. In particular, I'm pretty sure the mutex stuff doesn't require linking against the Boost.Thread library.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 12:43 PM, Kim Barrett wrote:
\The only thing that I need Boost.Thread for is serializing access to the random number generator -- I assume that most of the generators provided by Boost.Random can't tolerate being used by multiple threads simultaneously.
Boost.Thread is major overkill for that purpose, at least in my opinion, but until Boost.Atomic or something similar is approved, it's the only cross-platform way that I know of to safely serialize access without writing my own code for the purpose.
I believe much of Boost.Thread can be used header-only. In particular, I'm pretty sure the mutex stuff doesn't require linking against the Boost.Thread library.
That would make my life easier. :-) I don't see any reference to it in the Boost.Thread documentation though... if it turns out that I still need it after everything else is hashed out, I'll see what I can find in the source code. Thanks for the hint. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdtdUACgkQp9x9jeZ9/wQPKACg4i1eiUXLcl2h0aYNtm68hoAQ hU4AoLrzpyIBxyEAdw2/OOV3kkk7VFw+ =S00l -----END PGP SIGNATURE-----

On 05/02/2010 08:29 AM, Chad Nelson wrote:
On 05/02/2010 03:19 AM, Jeffrey Hellrung wrote: [...]
Regarding COW specifically: I'm guessing COW will be a tough sell,
I keep hearing that, but why? It's an internal detail, one that provides (or at least seems to) a very noticeable speed boost under some circumstances, and is disabled when it can't be safely used. Why would anyone, other than developers doing work on the library (i.e. me), care one way or another that the library uses it?
Because COW is not thread-safe ;) And I'm very curious how this speed "boost" (pun intended?) has come about. As Pavel has pointed out, yes, if you make 10 unmodified copies of a COW object, it's much faster than 10 unmodified copies of a non-COW object. But if I make 10 reference-to-consts of the same object, that's *even faster*. Can you give a "real" example where you'd actually *want* to produce an unmodified copy of an object, rather than just creating a reference-to-const? And doesn't the reference-to-const make your intentions ("Dude, I'm not modifying this thing!") that much clearer? The only example I can think of where COW might come in handy is if you do something like cow* p_x1 = new cow(); cow* p_x2 = new cow(*p_x1); // no deep copy / shared ownership // ... [A] Read from *p_x1, maybe? ... delete p_x1; // *p_x2 now has exclusive ownership I.e., the lifetimes of the handles are not in a subset relation (the lifetime of *p_x1 begins before, but also *ends* before, the lifetime of *p_x2). There's no way to avoid the copy with move semantics without affecting the code at [A] (*p_x1 is probably only guaranteed to be assignable at that point). However, I'd venture to say that 99% of the time, variable lifetimes are in fact subset related, and certainly make the reasoning of code easier. So, bottom line: Give me a real example of an algorithm where COW gives superior performance to move semantics, and I'll buy into the COW implementation. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 04:19 PM, Jeffrey Lee Hellrung, Jr. wrote:
Regarding COW specifically: I'm guessing COW will be a tough sell,
I keep hearing that, but why? It's an internal detail, one that provides (or at least seems to) a very noticeable speed boost under some circumstances, and is disabled when it can't be safely used. Why would anyone, other than developers doing work on the library (i.e. me), care one way or another that the library uses it?
Because COW is not thread-safe ;) And I'm very curious how this speed "boost" (pun intended?) has come about.
I've just posted the results of my testing. As to *why* it's that much faster, I can only provide educated guesses.
As Pavel has pointed out, yes, if you make 10 unmodified copies of a COW object, it's much faster than 10 unmodified copies of a non-COW object. But if I make 10 reference-to-consts of the same object, that's *even faster*. Can you give a "real" example where you'd actually *want* to produce an unmodified copy of an object, rather than just creating a reference-to-const? And doesn't the reference-to-const make your intentions ("Dude, I'm not modifying this thing!") that much clearer?
If something's not going to be modified, you might as well make it a constant reference. I assume the savings come from somewhere else, since I already use constant references wherever I can get away with it.
The only example I can think of where COW might come in handy is if you do something like
cow* p_x1 = new cow(); cow* p_x2 = new cow(*p_x1); // no deep copy / shared ownership // ... [A] Read from *p_x1, maybe? ... delete p_x1; // *p_x2 now has exclusive ownership
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
So, bottom line: Give me a real example of an algorithm where COW gives superior performance to move semantics, and I'll buy into the COW implementation.
I'll give you one better: the actual timings, which you can reproduce yourself if you doubt their accuracy. :-) Just let me know if you want the code I used to come up with them... the rules I read say that I'm not supposed to post any files to this list, so if you want them, I'll need to upload the changes somewhere. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvd6EkACgkQp9x9jeZ9/wTurgCg5H8jKM5lMR2QQZuM6Vwv9+/K skcAn0GPPpV8fT7mqHYjv9ckiZ4QJUUm =JF6s -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Sunday, May 02, 2010 11:02 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
I'll give you one better: the actual timings, which you can reproduce yourself if you doubt their accuracy. :-) Just let me know if you want the code I used to come up with them... the rules I read say that I'm not supposed to post any files to this list, so if you want them, I'll need to upload the changes somewhere.
What do you think about including the test and the figures on a perf directory on your repository? Best, Vicente

On 05/02/2010 02:02 PM, Chad Nelson wrote:
On 05/02/2010 04:19 PM, Jeffrey Lee Hellrung, Jr. wrote: [...]
Because COW is not thread-safe ;) And I'm very curious how this speed "boost" (pun intended?) has come about.
I've just posted the results of my testing. As to *why* it's that much faster, I can only provide educated guesses.
I think it is important to understand what the discrepancy is, because it may be that you're not writing your algorithms in a move-aware way, producing copies unnecessarily. This wouldn't surprise me if you wrote the original implementations with COW primarily in mind (which I can't blame you for). [...]
The only example I can think of where COW might come in handy is if you do something like
cow* p_x1 = new cow(); cow* p_x2 = new cow(*p_x1); // no deep copy / shared ownership // ... [A] Read from *p_x1, maybe? ... delete p_x1; // *p_x2 now has exclusive ownership
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
Hmmmm...I'm not quite sure what you mean. Maybe I'll take a look at your implementation of division.
So, bottom line: Give me a real example of an algorithm where COW gives superior performance to move semantics, and I'll buy into the COW implementation.
I'll give you one better: the actual timings, which you can reproduce yourself if you doubt their accuracy. :-) Just let me know if you want the code I used to come up with them... the rules I read say that I'm not supposed to post any files to this list, so if you want them, I'll need to upload the changes somewhere.
I'll take a look at the performance testing code when I get a chance, but I'm guessing a problem *could* be that you're not maximizing the opportunities to moven from or otherwise modify temporaries. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 07:20 PM, Jeffrey Lee Hellrung, Jr. wrote:
I've just posted the results of my testing. As to *why* it's that much faster, I can only provide educated guesses.
I think it is important to understand what the discrepancy is, because it may be that you're not writing your algorithms in a move-aware way, producing copies unnecessarily. This wouldn't surprise me if you wrote the original implementations with COW primarily in mind (which I can't blame you for).
I did, of course. But with the exception of operator+ and operator-, I don't see anything that could benefit from additional move-specific overloads.
So, bottom line: Give me a real example of an algorithm where COW gives superior performance to move semantics, and I'll buy into the COW implementation.
I'll give you one better: the actual timings, which you can reproduce yourself if you doubt their accuracy. :-) Just let me know if you want the code I used to come up with them... the rules I read say that I'm not supposed to post any files to this list, so if you want them, I'll need to upload the changes somewhere.
I'll take a look at the performance testing code when I get a chance, but I'm guessing a problem *could* be that you're not maximizing the opportunities to moven from or otherwise modify temporaries.
It's possible. Show me a better way and I'll adopt it. I don't think the operator+ and operator- are going to make a lot of difference to the results though. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkveKIoACgkQp9x9jeZ9/wT2KACg0ahGfqGKCRaa+K1R4qv6Bk+1 kagAoI1nfsFnDgGMf/80w4mb4IzMSAPp =fWUB -----END PGP SIGNATURE-----

On 05/02/2010 06:36 PM, Chad Nelson wrote:
On 05/02/2010 07:20 PM, Jeffrey Lee Hellrung, Jr. wrote:
I think it is important to understand what the discrepancy is, because it may be that you're not writing your algorithms in a move-aware way, producing copies unnecessarily. This wouldn't surprise me if you wrote the original implementations with COW primarily in mind (which I can't blame you for).
I did, of course. But with the exception of operator+ and operator-, I don't see anything that could benefit from additional move-specific overloads.
Oh, I think I misunderstood your comment in a previous message. You mean you don't see any advantage in modifying the arguments to functions other than operator+ and operator-? - Jeff

Chad Nelson wrote:
On 05/02/2010 04:19 PM, Jeffrey Lee Hellrung, Jr. wrote:
If something's not going to be modified, you might as well make it a constant reference.
I assume the savings come from somewhere else, since I already use constant references wherever I can get away with it.
The only example I can think of where COW might come in handy is if you do something like
cow* p_x1 = new cow(); cow* p_x2 = new cow(*p_x1); // no deep copy / shared ownership // ... [A] Read from *p_x1, maybe? ... delete p_x1; // *p_x2 now has exclusive ownership
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 3 May 2010, at 12:39, Stewart, Robert wrote:
Chad Nelson wrote:
On 05/02/2010 04:19 PM, Jeffrey Lee Hellrung, Jr. wrote:
If something's not going to be modified, you might as well make it a constant reference.
I assume the savings come from somewhere else, since I already use constant references wherever I can get away with it.
The only example I can think of where COW might come in handy is if you do something like
cow* p_x1 = new cow(); cow* p_x2 = new cow(*p_x1); // no deep copy / shared ownership // ... [A] Read from *p_x1, maybe? ... delete p_x1; // *p_x2 now has exclusive ownership
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
But, you save the cost of copying a large object. COW has many disadvantages, but how can you claim it is slower when you require a copy? It is worth noting that all implementations of the C++ standard library have gone through a similar process to this. I believe they all started out using COW std::strings, and the standard was written with various special cases specifcally to allow them. Most implementations are now phasing them out, as they are expensive to make thread-safe, and rvalue references remove many (but by no means all) of the cases where they were useful. Chris

Christopher Jefferson wrote:
On 3 May 2010, at 12:39, Stewart, Robert wrote:
Chad Nelson wrote:
algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
But, you save the cost of copying a large object. COW has many disadvantages, but how can you claim it is slower when you require a copy?
Did you miss the "but then need to modify it/them" part? The only reason for the copy was to have a mutable copy. Thus, the COW overhead was useless in that example. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

On 3 May 2010, at 13:28, Stewart, Robert wrote:
Christopher Jefferson wrote:
On 3 May 2010, at 12:39, Stewart, Robert wrote:
Chad Nelson wrote:
algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
But, you save the cost of copying a large object. COW has many disadvantages, but how can you claim it is slower when you require a copy?
Did you miss the "but then need to modify it/them" part? The only reason for the copy was to have a mutable copy. Thus, the COW overhead was useless in that example.
Apologises, I did indeed not read the message closely enough. My experience from COW std::string implementation is that with care, rvalue references and copy elising, you can get away with almost no unnecessary copies. In particular, in C++0x having the compiler always move local variables in return statements is a big win. How much of this gain you would get in a plain C++03 compiler, with boost::move but without users annotating any moves or rvalues to their code, I don't know. Chris

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 08:28 AM, Stewart, Robert wrote:
But, you save the cost of copying a large object. COW has many disadvantages, but how can you claim it is slower when you require a copy?
Did you miss the "but then need to modify it/them" part? The only reason for the copy was to have a mutable copy. Thus, the COW overhead was useless in that example.
Not exactly useless -- I *do* know enough to avoid things that are completely useless. :-) The purpose was to initialize them to the value of another integer, such as a parameter, before going into a loop that modifies them based on their current values. With copy-on-write, the initial allocation can be skipped, which (depending on the number of times it needs to loop) can be a significant savings. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve9jIACgkQp9x9jeZ9/wTgagCg4CyNXBelDY6JL/Uxq3x3FV0/ WekAoL+wDKQ3MUlZU55WyWDLuaYAoNV2 =q/F+ -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/03/2010 08:28 AM, Stewart, Robert wrote:
But, you save the cost of copying a large object. COW has many disadvantages, but how can you claim it is slower when you require a copy?
Did you miss the "but then need to modify it/them" part? The only reason for the copy was to have a mutable copy. Thus, the COW overhead was useless in that example.
Not exactly useless -- I *do* know enough to avoid things that are completely useless. :-) The purpose was to initialize them to the value of another integer, such as a parameter, before going into a loop that modifies them based on their current values. With copy-on-write, the initial allocation can be skipped, which (depending on the number of times it needs to loop) can be a significant savings.
You say you copy an instance and then mutate it. Guess what! The copy involves manipulating the reference count and the mutating operations must all check whether the instance is unique. The first mutating operation actually makes a unique copy and the rest just check superfluously. Thus, in the cited example, since there will be a mutated copy, COW pessimizes the code. In single threaded code, the overhead is small, assuming good branch prediction in the processor, but it isn't zero. (When used in MT code, of course, the overhead is worse.) My point is your example in no way justifies COW. Provide another real use case from your library that isn't served by move semantics, and you'll have convinced folks that COW is appropriate. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 12:46 PM, Stewart, Robert wrote:
Not exactly useless -- I *do* know enough to avoid things that are completely useless. :-) The purpose was to initialize them to the value of another integer, such as a parameter, before going into a loop that modifies them based on their current values. With copy-on-write, the initial allocation can be skipped, which (depending on the number of times it needs to loop) can be a significant savings.
You say you copy an instance and then mutate it. Guess what! The copy involves manipulating the reference count and the mutating operations must all check whether the instance is unique. The first mutating operation actually makes a unique copy and the rest just check superfluously.
The first operation *may* make a unique copy, if the operation results in a change to the number. There's no guarantee that it will. For example, in earlier versions of the library (when the divide function wasn't split up the way it is now), I needed to do a calculation to see whether the divisor and dividend needed to be normalized. If they did (about half the time), they had to be mutated; if they didn't, they kept their original values. With copy-on-write, it was simple to make mutable copies of them, and only actually mutate them (and pay the price for it) when it was needed.
Thus, in the cited example, since there will be a mutated copy, COW pessimizes the code. In single threaded code, the overhead is small, assuming good branch prediction in the processor, but it isn't zero. (When used in MT code, of course, the overhead is worse.)
When used in MT code, the library doesn't use copy-on-write, so that's not a problem.
My point is your example in no way justifies COW. Provide another real use case from your library that isn't served by move semantics, and you'll have convinced folks that COW is appropriate.
I already have: it's quite a bit faster. :-) Though as I said, I may have identify something that's slowing down the move stuff. I'll post more information when I have it. I'll be happy to remove copy-on-write if I can make the library as fast with move semantics. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfCn0ACgkQp9x9jeZ9/wR6jgCfa8qyIUZhUU7jO4hrDgT9U8Ms UkAAoIsqbBUrcWOGnKQ5uyK6mZW0RRZx =UOqu -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/03/2010 12:46 PM, Stewart, Robert wrote:
Not exactly useless -- I *do* know enough to avoid things that are completely useless. :-) The purpose was to initialize them to the value of another integer, such as a parameter, before going into a loop that modifies them based on their current values. With copy-on-write, the initial allocation can be skipped, which (depending on the number of times it needs to loop) can be a significant savings.
You say you copy an instance and then mutate it. Guess what! The copy involves manipulating the reference count and the mutating operations must all check whether the instance is unique. The first mutating operation actually makes a unique copy and the rest just check superfluously.
The first operation *may* make a unique copy, if the operation results in a change to the number. There's no guarantee that it will.
Yes, in that case COW prevents premature allocation/copying, but that's not how you phrased the example originally. We've been arguing at cross-purposes, apparently. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 03.05.2010 at 15:39 Stewart, Robert wrote :
Chad Nelson wrote:
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic and yes, i think that cow is pretty useful here especially complemented by "rvalue&move awareness" also one should take into account that implicit sharing (cow) can be made thread safe with little effort from the author (just a couple of atomic ops) i.e. as soon as atomic lib becomes a part of boost cow implementation of xint can be made thread safe by your (lib user) desire i'm glad that everyone switched to the implementation because it means there is nothing criminally wrong with the interface said that, we can expect the implementation to become optimal in time so the main work is done i guess congratulations! -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
Chad Nelson wrote:
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic
Once again, allow me to point out that the copy was being made in order to mutate the copy. The COW operations are superfluous in that case. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 03.05.2010 at 19:48 Stewart, Robert wrote :
DE wrote:
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic
Once again, allow me to point out that the copy was being made in order to mutate the copy. The COW operations are superfluous in that case.
i understand this point but i see no conflict between those two statements -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
DE wrote:
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic
Once again, allow me to point out that the copy was being made in order to mutate the copy. The COW operations are superfluous in that case.
i understand this point but i see no conflict between those two statements
There is no conflict other than that your response was directed to my statement that the COW overhead was superfluous in the context I addressed. Thus, using COW to satisfy the stated example pessimized the code. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 03.05.2010 at 20:39 Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
DE wrote:
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic
Once again, allow me to point out that the copy was being made in order to mutate the copy. The COW operations are superfluous in that case.
i understand this point but i see no conflict between those two statements
There is no conflict other than that your response was directed to my statement that the COW overhead was superfluous in the context I addressed. Thus, using COW to satisfy the stated example pessimized the code.
it does indeed but the pessimization is negligible compared to the cost of an operation itself i suddenly have remebered a rule on optimization: measure, then optimize in other words: find a bottleneck and only then optimize the code causing it in this thread things look the other way around you guys make a guess and ask to change/optimize the code using that guess as the basis sorry, i consider it wrong in fact it must be like this: - i use it in a <usecase>, i profiled it and found a bottleneck in the following piece of code... otherwise there is a big chance we are wasting each others time making guesses and arguing about implementation details because optimizations born from that may be worthless -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
DE wrote:
but i see no conflict between those two statements
There is no conflict other than that your response was directed to my statement that the COW overhead was superfluous in the context I addressed. Thus, using COW to satisfy the stated example pessimized the code.
it does indeed but the pessimization is negligible compared to the cost of an operation itself
We've been discussing whether COW is needed. The example cited didn't justify it, so any overhead it adds is unnecessary. We're awaiting word on what may be wrong with the application of move semantics to explain why COW is needed. If that rectifies the situation, then COW should be removed. If not, keep it. I've never argued that it must be removed. I just refuted the one example provided and wondered if there was a problem with the move semantics.
i suddenly have remebered a rule on optimization: measure, then optimize in other words: find a bottleneck and only then optimize the code causing it
That's exactly what Chad did. That's why he added COW. With the addition of move semantics, there's reason to think it shouldn't be needed.
in this thread things look the other way around you guys make a guess and ask to change/optimize the code using that guess as the basis sorry, i consider it wrong
There is nothing wrong with trying to poke holes in a design or implementation. From experience, we know that COW is usually a pessimization rather than an optimization in MT code, so it is usually avoided altogether for simplicity. Its need raises red flags. When the tests suggest that the library is truly faster with COW, we're a little skeptical and want to understand why. This is the scientific method in action.
in fact it must be like this: - i use it in a <usecase>, i profiled it and found a bottleneck in the following piece of code...
otherwise there is a big chance we are wasting each others time making guesses and arguing about implementation details because optimizations born from that may be worthless
I disagree. The COW issue will be raised during review. Chad needs to be ready to defend its use then. Having done so now means he can explain it in the docs and avoid such discussions during the review. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 03.05.2010 at 21:37 Stewart, Robert wrote :
DE wrote:
i suddenly have remebered a rule on optimization: measure, then optimize in other words: find a bottleneck and only then optimize the code causing it
That's exactly what Chad did. That's why he added COW. With the addition of move semantics, there's reason to think it shouldn't be needed.
in this thread things look the other way around you guys make a guess and ask to change/optimize the code using that guess as the basis sorry, i consider it wrong
There is nothing wrong with trying to poke holes in a design or implementation. From experience, we know that COW is usually a pessimization rather than an optimization in MT code, so it is usually avoided altogether for simplicity. Its need raises red flags. When the tests suggest that the library is truly faster with COW, we're a little skeptical and want to understand why. This is the scientific method in action.
in fact it must be like this: - i use it in a <usecase>, i profiled it and found a bottleneck in the following piece of code...
otherwise there is a big chance we are wasting each others time making guesses and arguing about implementation details because optimizations born from that may be worthless
I disagree. The COW issue will be raised during review. Chad needs to be ready to defend its use then. Having done so now means he can explain it in the docs and avoid such discussions during the review.
i agree with almost all you've just said however chad not only stated that his cow is faster (a pun intended) but also provided numbers (test results -- read "the proof") so that's you who must prove the cow is slower than whatsoever or misapplied, not chad -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
i agree with almost all you've just said however chad not only stated that his cow is faster (a pun intended) but also provided numbers (test results -- read "the proof") so that's you who must prove the cow is slower than whatsoever or misapplied, not chad
I've already noted that his application of move semantics was being reviewed. (I think it was Jeffrey Hellrung who was looking into it.) I also noted that we'd like to understand why. Those points remain to be fulfilled, but it doesn't make our approach faulty. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 03.05.2010 at 22:07 Stewart, Robert wrote :
DE wrote:
i agree with almost all you've just said however chad not only stated that his cow is faster (a pun intended) but also provided numbers (test results -- read "the proof") so that's you who must prove the cow is slower than whatsoever or misapplied, not chad
I've already noted that his application of move semantics was being reviewed. (I think it was Jeffrey Hellrung who was looking into it.) I also noted that we'd like to understand why. Those points remain to be fulfilled, but it doesn't make our approach faulty.
my point is if you want to "understand why" then why don't you look at the sources instead of making guesses? that will answer your question(s) and make the discussion more constructive -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "Stewart, Robert" <boost@lists.boost.org> Sent: Monday, May 03, 2010 9:02 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 03.05.2010 at 22:07 Stewart, Robert wrote :
DE wrote:
i agree with almost all you've just said however chad not only stated that his cow is faster (a pun intended) but also provided numbers (test results -- read "the proof") so that's you who must prove the cow is slower than whatsoever or misapplied, not chad
I've already noted that his application of move semantics was being reviewed. (I think it was Jeffrey Hellrung who was looking into it.) I also noted that we'd like to understand why. Those points remain to be fulfilled, but it doesn't make our approach faulty.
my point is if you want to "understand why" then why don't you look at the sources instead of making guesses? that will answer your question(s) and make the discussion more constructive
In a post from yesterday it was said that the arithmetic operators were not implemented following move semantics. The signatures were given, but no replay to this post has been done yet. I'm sure that the poster was looking into the sources. Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 03:55 PM, vicente.botet wrote:
my point is if you want to "understand why" then why don't you look at the sources instead of making guesses? that will answer your question(s) and make the discussion more constructive
In a post from yesterday it was said that the arithmetic operators were not implemented following move semantics. The signatures were given, but no replay to this post has been done yet. I'm sure that the poster was looking into the sources.
Did I miss a message? I've been trying to answer everything that seemed to need an answer. I don't see any messages that include function signatures that I didn't respond to...? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfTh8ACgkQp9x9jeZ9/wRm/QCffTdaU6t7/GwTbBFMcH+r9xjI /IcAoPjXAUF6vLGe2LYsuaU0bXdNDUyn =rzWu -----END PGP SIGNATURE-----

on 03.05.2010 at 23:55 vicente.botet wrote :
In a post from yesterday it was said that the arithmetic operators were not implemented following move semantics. The signatures were given, but no replay to this post has been done yet. I'm sure that the poster was looking into the sources.
actually i don't see a reason to implement them that way rather they should be implemented either of two ways type operator@(type, const type&); type operator#(const type&, const type&); but not simultaneously in the first case move semantics will take place where appropriate -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

On 5/4/2010 12:29 AM, DE wrote:
on 03.05.2010 at 23:55 vicente.botet wrote :
In a post from yesterday it was said that the arithmetic operators were not implemented following move semantics. The signatures were given, but no replay to this post has been done yet. I'm sure that the poster was looking into the sources.
actually i don't see a reason to implement them that way rather they should be implemented either of two ways
type operator@(type, const type&); type operator#(const type&, const type&);
but not simultaneously in the first case move semantics will take place where appropriate
No good :( Assuming only the *possibility* of reusing resources from your arguments, you want the signature operator+(T,T) if you're adding 2 rvalues, but the signature operator+(const T&, const T&) if you're adding 2 lvalues (so you don't make unnecessary copies compared to passing by value). Unfortunately, you can't have both (ambiguous overload resolution) :/ The only way to get something semantically equivalent is to overload by rvalue reference. If reuse of resources is *unconditional*, then, sure, pass by value (as long as the swapping/moving is cheap). If reuse of resources *never* happens, then, sure, pass by reference-to-const. Otherwise, the optimal approach is to provide all combinations of rvalue reference and lvalue reference-to-const parameters (in c++03). - Jeff

on 04.05.2010 at 18:54 Jeffrey Lee Hellrung, Jr. wrote :
On 5/4/2010 12:29 AM, DE wrote:
actually i don't see a reason to implement them that way rather they should be implemented either of two ways
type operator@(type, const type&); type operator#(const type&, const type&);
but not simultaneously in the first case move semantics will take place where appropriate
No good :( Assuming only the *possibility* of reusing resources from your arguments, you want the signature operator+(T,T) if you're adding 2 rvalues, but the signature operator+(const T&, const T&) if you're adding 2 lvalues (so you don't make unnecessary copies compared to passing by value). Unfortunately, you can't have both (ambiguous overload resolution) :/ The only way to get something semantically equivalent is to overload by rvalue reference.
If reuse of resources is *unconditional*, then, sure, pass by value (as long as the swapping/moving is cheap). If reuse of resources *never* happens, then, sure, pass by reference-to-const. Otherwise, the optimal approach is to provide all combinations of rvalue reference and lvalue reference-to-const parameters (in c++03).
sure you are absolutely right i meant only the "unconditional" case -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "Stewart, Robert" <boost@lists.boost.org> Sent: Monday, May 03, 2010 7:16 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 03.05.2010 at 20:39 Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
DE wrote:
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic
Once again, allow me to point out that the copy was being made in order to mutate the copy. The COW operations are superfluous in that case.
i understand this point but i see no conflict between those two statements
There is no conflict other than that your response was directed to my statement that the COW overhead was superfluous in the context I addressed. Thus, using COW to satisfy the stated example pessimized the code.
it does indeed but the pessimization is negligible compared to the cost of an operation itself
i suddenly have remebered a rule on optimization: measure, then optimize in other words: find a bottleneck and only then optimize the code causing it in this thread things look the other way around you guys make a guess and ask to change/optimize the code using that guess as the basis sorry, i consider it wrong in fact it must be like this: - i use it in a <usecase>, i profiled it and found a bottleneck in the following piece of code...
otherwise there is a big chance we are wasting each others time making guesses and arguing about implementation details because optimizations born from that may be worthless
Do you mean that Chad should remove its COW optimization and mesure and optimize the bottleneck? Vicente

on 03.05.2010 at 21:41 vicente.botet wrote :
Do you mean that Chad should remove its COW optimization and mesure and optimize the bottleneck? //^^ "his" better suits here i think
nope that's you who must provide evidence that cow spoils things -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "Stewart, Robert" <boost@lists.boost.org> Sent: Monday, May 03, 2010 5:44 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
i'm glad that everyone switched to the implementation because it means there is nothing criminally wrong with the interface said that, we can expect the implementation to become optimal in time so the main work is done i guess
I have some question about the interface. I know that these functions appears on N1744 bool getbit( intege r const &, size _t ); void setbit( intege r &, size_t ); void clearbit( integer &, size_ t ); But are these really necessary? A use case? The std::numeric_limits specialization defines functions that return 0 with a comment 00298 namespace std { 00299 template<> 00300 class numeric_limits<boost::xint::integer> { 00301 public: 00302 static const bool is_specialized = true; 00303 00304 static boost::xint::integer min() throw() { return 0; } // Not applicable 00305 static boost::xint::integer max() throw() { return 0; } // Not applicable If a value can not be given, shouldn't these be undefined? Or should these functions return -infinity, infinity?xint::integer is a signed integer. It is worth having an unsigned integer xint::uinteger? If not why?Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 12:42 PM, vicente.botet wrote:
I have some question about the interface.
I know that these functions appears on N1744 bool getbit( intege r const &, size _t ); void setbit( intege r &, size_t ); void clearbit( integer &, size_ t );
But are these really necessary? A use case?
setbit can be used to create a large power-of-two more efficiently than a shift function -- that's what the pow2 convenience function uses. I haven't found a use for the other two, but I imagine that the use case for them was using a large integer as an unlimited-length bit field.
The std::numeric_limits specialization defines functions that return 0 with a comment
00298 namespace std { 00299 template<> 00300 class numeric_limits<boost::xint::integer> { 00301 public: 00302 static const bool is_specialized = true; 00303 00304 static boost::xint::integer min() throw() { return 0; } // Not applicable 00305 static boost::xint::integer max() throw() { return 0; } // Not applicable
If a value can not be given, shouldn't these be undefined?
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
Or should these functions return -infinity, infinity?
If I had such values, I'd use them there.
xint::integer is a signed integer. It is worth having an unsigned integer xint::uinteger? If not why?
I'd say the question is why have one, rather than why not. :-) There are only two advantages I know of to unsigned int over int: you never have to check whether it's negative, and you get one extra bit's worth of room, allowing you to work with larger numbers. The second isn't a problem here, and the first can easily be dealt with. Is there a use case where a signed integer wouldn't be sufficient? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfBl4ACgkQp9x9jeZ9/wSxAQCfcRsqDgyIcyv/HwoYxEQq60om 0HkAnRlnNLGTMZ4rk3aggDsnMyl52mb9 =DWyG -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 7:22 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/03/2010 12:42 PM, vicente.botet wrote:
I have some question about the interface.
I know that these functions appears on N1744 bool getbit( intege r const &, size _t ); void setbit( intege r &, size_t ); void clearbit( integer &, size_ t );
But are these really necessary? A use case?
setbit can be used to create a large power-of-two more efficiently than a shift function -- that's what the pow2 convenience function uses. I haven't found a use for the other two, but I imagine that the use case for them was using a large integer as an unlimited-length bit field.
OK. I see.
The std::numeric_limits specialization defines functions that return 0 with a comment
00298 namespace std { 00299 template<> 00300 class numeric_limits<boost::xint::integer> { 00301 public: 00302 static const bool is_specialized = true; 00303 00304 static boost::xint::integer min() throw() { return 0; } // Not applicable 00305 static boost::xint::integer max() throw() { return 0; } // Not applicable
If a value can not be given, shouldn't these be undefined?
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error.
Or should these functions return -infinity, infinity?
If I had such values, I'd use them there.
xint::integer is a signed integer. It is worth having an unsigned integer xint::uinteger? If not why?
I'd say the question is why have one, rather than why not. :-)
Well imagine you have decimal numbers. You can define any integer using decimal number with 0 decimal digits. Does this means that you don't need a integer type?
There are only two advantages I know of to unsigned int over int: you never have to check whether it's negative, and you get one extra bit's worth of room, allowing you to work with larger numbers. The second isn't a problem here, and the first can easily be dealt with. Is there a use case where a signed integer wouldn't be sufficient?
Well if in my application the domain type is unsigned by nature, I don't see why I will define it as signed one if I can avoid it. Vicente

on 03.05.2010 at 21:39 vicente.botet wrote :
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error. ...
std::numeric_limits comes from C++ standard so you must consult the standard to figure out why is std::numeric_limits designed the way it is -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

On 5/3/2010 10:52 AM, DE wrote:
on 03.05.2010 at 21:39 vicente.botet wrote :
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error. ...
std::numeric_limits comes from C++ standard so you must consult the standard to figure out why is std::numeric_limits designed the way it is
I think if std::numeric_limits<T>::is_bounded is false, then min and max are "defined" to be meaningless. - Jeff

----- Original Message ----- From: "Jeffrey Lee Hellrung, Jr." <jhellrung@ucla.edu> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 8:01 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
On 5/3/2010 10:52 AM, DE wrote:
on 03.05.2010 at 21:39 vicente.botet wrote :
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error. ...
std::numeric_limits comes from C++ standard so you must consult the standard to figure out why is std::numeric_limits designed the way it is
I think if std::numeric_limits<T>::is_bounded is false, then min and max are "defined" to be meaningless.
Thanks for clarification. It is much better in this way. Best, Vicente

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "vicente.botet" <boost@lists.boost.org> Sent: Monday, May 03, 2010 7:52 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 03.05.2010 at 21:39 vicente.botet wrote :
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error. ...
std::numeric_limits comes from C++ standard so you must consult the standard to figure out why is std::numeric_limits designed the way it is
I don't think I have said nothing that merits this answer. I know perfectly how std::numeric_limits is designed. I'm just saying that if XInt defines std::numeric_limits<boost::xint::integer>::max() as 0, no generic code can make use of this. Please read the posts carefuly before replying. Vicente

----- Original Message ----- From: "vicente.botet" <vicente.botet@wanadoo.fr> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 9:32 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "vicente.botet" <boost@lists.boost.org> Sent: Monday, May 03, 2010 7:52 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 03.05.2010 at 21:39 vicente.botet wrote :
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error. ...
std::numeric_limits comes from C++ standard so you must consult the standard to figure out why is std::numeric_limits designed the way it is
I don't think I have said nothing that merits this answer. I know perfectly how std::numeric_limits is designed. I'm just saying that if XInt defines std::numeric_limits<boost::xint::integer>::max() as 0, no generic code can make use of this.
Please read the posts carefuly before replying.
My bad, I missed the is_bounded detail. Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Monday 03 May 2010, vicente.botet wrote:
I know perfectly how std::numeric_limits is designed. I'm just saying that if XInt defines std::numeric_limits<boost::xint::integer>::max() as 0, no generic code can make use of this.
Couldn't generic code also check is_bounded? This page http://msdn.microsoft.com/en-us/library/69bwfeks(VS.80).aspx says the return value of numeric_limits::min/max only has to be meaningful if is_bounded is true, etc. I assume that's taken from the standard, but haven't checked. Speaking of numeric_limits, anyone know why they defined numeric_limits::min() to mean something completely different for floating and integer types? numeric_limits<double>::min is: 2.22507e-308 numeric_limits<int>::min is: -2147483648 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAkvfKgcACgkQ5vihyNWuA4Vu6QCfVJWVzvT1U2WUa4y6gXDTj0Wt FfMAoL6wH1guFtU0LWwGv1Ot/UMeGhx0 =gVKc -----END PGP SIGNATURE-----

Frank Mori Hess wrote:
Speaking of numeric_limits, anyone know why they defined numeric_limits::min() to mean something completely different for floating and integer types?
numeric_limits<double>::min is: 2.22507e-308 numeric_limits<int>::min is: -2147483648
That is a pain, isn't it? I can only assume it was to avoid adding yet more attributes. (You'd need biggest, smallest, maximum, and minimum, or some such set to express everything.) Floating point types don't have asymmetrical ranges like integral types. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 04.05.2010 at 15:34 Stewart, Robert wrote :
Frank Mori Hess wrote:
Speaking of numeric_limits, anyone know why they defined numeric_limits::min() to mean something completely different for floating and integer types?
numeric_limits<double>::min is: 2.22507e-308 numeric_limits<int>::min is: -2147483648
That is a pain, isn't it? I can only assume it was to avoid adding yet more attributes. (You'd need biggest, smallest, maximum, and minimum, or some such set to express everything.) Floating point types don't have asymmetrical ranges like integral types.
not that much typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max(); -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
Frank Mori Hess wrote:
Speaking of numeric_limits, anyone know why they defined numeric_limits::min() to mean something completely different for floating and integer types?
numeric_limits<double>::min is: 2.22507e-308 numeric_limits<int>::min is: -2147483648
That is a pain, isn't it? I can only assume it was to avoid adding yet more attributes. (You'd need biggest, smallest, maximum, and minimum, or some such set to express everything.) Floating point types don't have asymmetrical ranges like integral types.
not that much
typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max();
That only works for unsigned types. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 04.05.2010 at 15:44 Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
Frank Mori Hess wrote:
Speaking of numeric_limits, anyone know why they defined numeric_limits::min() to mean something completely different for floating and integer types?
numeric_limits<double>::min is: 2.22507e-308 numeric_limits<int>::min is: -2147483648
That is a pain, isn't it? I can only assume it was to avoid adding yet more attributes. (You'd need biggest, smallest, maximum, and minimum, or some such set to express everything.) Floating point types don't have asymmetrical ranges like integral types.
not that much
typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max();
That only works for unsigned types.
it does work for bounded signed and unsigned integers, unbounded unsigned integers and also for floating point values (with denormalization) so no, not that much -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
DE wrote:
typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max();
That only works for unsigned types.
it does work for bounded signed and unsigned integers, unbounded unsigned integers and also for floating point values (with denormalization)
Signed integer types use two's complement, so the absolute value of the largest positive and largest negative value differs. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 04.05.2010 at 18:22 Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
DE wrote:
typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max();
That only works for unsigned types.
it does work for bounded signed and unsigned integers, unbounded unsigned integers and also for floating point values (with denormalization)
Signed integer types use two's complement, so the absolute value of the largest positive and largest negative value differs.
so what? honestly i don't catch your point -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
DE wrote:
typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max();
That only works for unsigned types.
it does work for bounded signed and unsigned integers, unbounded unsigned integers and also for floating point values (with denormalization)
Signed integer types use two's complement, so the absolute value of the largest positive and largest negative value differs.
so what? honestly i don't catch your point
-traits::max() != largest negative _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 04.05.2010 at 18:49 Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
DE wrote:
Stewart, Robert wrote :
DE wrote:
typedef std::numeric_limits<type> traits; const type realy_min = traits::is_integer ? traits::min() : -traits::max();
That only works for unsigned types.
it does work for bounded signed and unsigned integers, unbounded unsigned integers and also for floating point values (with denormalization)
Signed integer types use two's complement, so the absolute value of the largest positive and largest negative value differs.
so what? honestly i don't catch your point
-traits::max() != largest negative
'-traits::max()' part is used for floating point numbers only so i guess it does equal the largest (in magnitude) representable negative number -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
-traits::max() != largest negative
'-traits::max()' part is used for floating point numbers only so i guess it does equal the largest (in magnitude) representable negative number
I was just reading too fast. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 03.05.2010 at 23:32 vicente.botet wrote :
std::numeric_limits comes from C++ standard so you must consult the standard to figure out why is std::numeric_limits designed the way it is
I don't think I have said nothing that merits this answer. I know perfectly how std::numeric_limits is designed. I'm just saying that if XInt defines std::numeric_limits<boost::xint::integer>::max() as 0, no generic code can make use of this.
Please read the posts carefuly before replying.
sorry if that seemed offensive to you but you should have consulted the standard before asking such questions here is a quote for you: 18.2.1.2 numeric_limits members [lib.numeric.limits.members] static T min() throw(); 1 Minimum finite value. 2 For floating types with denormalization, returns the minimum positive normalized value. 3 Meaningful for all specializations in which is_bounded != false, or is_bounded == false && is_signed == false. static T max() throw(); 4 Maximum finite value. 5 Meaningful for all specializations in which is_bounded != false. does this answer your question regarding min()/max() specializations? -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 01:39 PM, vicente.botet wrote:
The std::numeric_limits specialization defines functions that return 0 with a comment
00298 namespace std { 00299 template<> 00300 class numeric_limits<boost::xint::integer> { 00301 public: 00302 static const bool is_specialized = true; 00303 00304 static boost::xint::integer min() throw() { return 0; } // Not applicable 00305 static boost::xint::integer max() throw() { return 0; } // Not applicable
If a value can not be given, shouldn't these be undefined?
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error.
if (numeric_limits<T>::is_bounded) { // do something using max() and min() } That wouldn't even compile if definitions of max and min weren't provided, even though it's perfectly legal and useful.
xint::integer is a signed integer. It is worth having an unsigned integer xint::uinteger? If not why?
I'd say the question is why have one, rather than why not. :-)
Well imagine you have decimal numbers. You can define any integer using decimal number with 0 decimal digits. Does this means that you don't need a integer type?
Depends on the case. If floating-point numbers were just as fast and efficient as integers, you might not. I've seen at least one programming language where every number is a floating-point one, at least potentially (I don't recall which one though... possibly Common Lisp, which I haven't looked at in a long time).
There are only two advantages I know of to unsigned int over int: you never have to check whether it's negative, and you get one extra bit's worth of room, allowing you to work with larger numbers. The second isn't a problem here, and the first can easily be dealt with. Is there a use case where a signed integer wouldn't be sufficient?
Well if in my application the domain type is unsigned by nature, I don't see why I will define it as signed one if I can avoid it.
Because programmer time is a finite resource. Provide a good use case for an unsigned large-integer and I'll add one, otherwise I'd rather spend my limited time on more important things. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfEEQACgkQp9x9jeZ9/wT6sQCg1HXmaoF2U/Wemu/hkukURaOt f5wAn1i++pzVQsFFFOMpkbUvjSeSBEQb =/Byp -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Monday, May 03, 2010 8:04 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/03/2010 01:39 PM, vicente.botet wrote:
The std::numeric_limits specialization defines functions that return 0 with a comment
00298 namespace std { 00299 template<> 00300 class numeric_limits<boost::xint::integer> { 00301 public: 00302 static const bool is_specialized = true; 00303 00304 static boost::xint::integer min() throw() { return 0; } // Not applicable 00305 static boost::xint::integer max() throw() { return 0; } // Not applicable
If a value can not be given, shouldn't these be undefined?
If they weren't defined, could generic code work with them? The GCC specialization for the int type includes all of the members, even the ones that are only applicable to floating-point values, so I did too.
How generic code could work if the returned values are not applicable, not significant. I would prefer a compile error than a runtime error.
if (numeric_limits<T>::is_bounded) { // do something using max() and min() }
That wouldn't even compile if definitions of max and min weren't provided, even though it's perfectly legal and useful.
Yes, I missed the is_bounded detail. I understand now.
xint::integer is a signed integer. It is worth having an unsigned integer xint::uinteger? If not why?
I'd say the question is why have one, rather than why not. :-)
Well imagine you have decimal numbers. You can define any integer using decimal number with 0 decimal digits. Does this means that you don't need a integer type?
Depends on the case. If floating-point numbers were just as fast and efficient as integers, you might not. I've seen at least one programming language where every number is a floating-point one, at least potentially (I don't recall which one though... possibly Common Lisp, which I haven't looked at in a long time).
We are in C++.
There are only two advantages I know of to unsigned int over int: you never have to check whether it's negative, and you get one extra bit's worth of room, allowing you to work with larger numbers. The second isn't a problem here, and the first can easily be dealt with. Is there a use case where a signed integer wouldn't be sufficient?
Well if in my application the domain type is unsigned by nature, I don't see why I will define it as signed one if I can avoid it.
Because programmer time is a finite resource. Provide a good use case for an unsigned large-integer and I'll add one, otherwise I'd rather spend my limited time on more important things.
I was trying to find possible holes on the library. I have too other more important things to do. Vicente

On 3 May 2010 14:04, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
if (numeric_limits<T>::is_bounded) { // do something using max() and min() }
That wouldn't even compile if definitions of max and min weren't provided, even though it's perfectly legal and useful.
It will also give compiler warnings in certain compilers about branching on a constant. Generally the "correct" way is to only compile the max- or min-using code if is_bounded is true, by enable_if, specialization, or some other mechanism.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 07:00 PM, Scott McMurray wrote:
if (numeric_limits<T>::is_bounded) { // do something using max() and min() }
That wouldn't even compile if definitions of max and min weren't provided, even though it's perfectly legal and useful.
It will also give compiler warnings in certain compilers about branching on a constant.
Generally the "correct" way is to only compile the max- or min-using code if is_bounded is true, by enable_if, specialization, or some other mechanism.
I was just providing some code pointing out why max and min had to be defined in numeric_limits<xint::integer>, even though they only return zeros. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfXUwACgkQp9x9jeZ9/wTb8ACfR7pC6jHqPhM8moO2dUwv1fsF niMAn3BC1CTXG3qP4SXlMxVW+AxoFSYb =4jO4 -----END PGP SIGNATURE-----

On 3 May 2010 19:33, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
I was just providing some code pointing out why max and min had to be defined in numeric_limits<xint::integer>, even though they only return zeros.
And I was pointing out that, no, they don't *have* to be defined for generic code to work, since is_bounded is a compile-time constant, making it possible to not compile the max()- and min()-using code when it has value false. The standard seems to only talk about fundamental types having specializations, so it's unclear to me whether members that are not "meaningful" are meant to be provided or not.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 07:37 PM, Scott McMurray wrote:
I was just providing some code pointing out why max and min had to be defined in numeric_limits<xint::integer>, even though they only return zeros.
And I was pointing out that, no, they don't *have* to be defined for generic code to work, since is_bounded is a compile-time constant, making it possible to not compile the max()- and min()-using code when it has value false.
Possible, yes -- but it relies on a Boost library to do so.
The standard seems to only talk about fundamental types having specializations, so it's unclear to me whether members that are not "meaningful" are meant to be provided or not.
It wouldn't be possible for your average developer to write generic code that did that sort of thing with only the standard library to work with. As such, and because GCC provides all members in all types, I read it that all numeric_limits specializations should provide all members. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfaHMACgkQp9x9jeZ9/wS5DACdF0i+E09M27GpLQiydxwu3XiQ sYEAn1HLlx/paplJWgM+YHfBLyphWTDL =u7Pv -----END PGP SIGNATURE-----

On 3 May 2010 20:21, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
Possible, yes -- but it relies on a Boost library to do so.
Not in the slightest. You can always use specialization to do it, like: template <typename T, bool S = std::numeric_limits<T>::is_specialized> struct foo { void bar() { ... no min/max ...} }; template <typename T> struct foo<T, true> { void bar() { ... has min/max ...} };

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 08:32 PM, Scott McMurray wrote:
Possible, yes -- but it relies on a Boost library to do so.
Not in the slightest. You can always use specialization to do it, like:
template <typename T, bool S = std::numeric_limits<T>::is_specialized> struct foo { void bar() { ... no min/max ...} }; template <typename T> struct foo<T, true> { void bar() { ... has min/max ...} };
(I assume that's supposed to be std::numeric_limits<T>::is_bounded, rather than is_specialized.) Would your average developer know about that sort of thing? I've been using C++ since 1987, and I'd never seen it until a couple months ago. And then only by digging into the Boost.TypeTraits library's source code to figure out how it worked. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfcFAACgkQp9x9jeZ9/wSkxQCdF+OHqh67IvvDcJs2Kl999q+W 8rMAni9zWwwpWgbRu/Za/B1KMH5o+b4X =fX+6 -----END PGP SIGNATURE-----

On 3 May 2010 20:54, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
Would your average developer know about that sort of thing? I've been using C++ since 1987, and I'd never seen it until a couple months ago. And then only by digging into the Boost.TypeTraits library's source code to figure out how it worked.
Does "your average developer" even write templates that use the extra power than templates offer over generics? I'm not convinced that Boost should be all that concerned about developers attempting to write generic code while ignorant of fundamental template building blocks. The trick behind enable_if has been known by the acronym SFINAE since at least 2002, thanks to Vandevoorde and Josuttis's book [1]. Alexandrescu's _Modern C++ Design_ [2] -- containing templates far more complicated than a simple specialization -- was published more than 20 months earlier than that. These are not bleeding-edge or secret techniques. That said, I'm not sure whether it's better to not provide min and max, and thus catch code that uses them without checking is_bounded, or to possibly make it easier to correctly write code that does check is_bounded. And who knows -- maybe making it easy with SFINAE would mean that those developers that don't know will go looking for the clean way and learn a new tool. [1] http://en.wikipedia.org/wiki/SFINAE [2] http://erdani.com/book/main.html

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 09:22 PM, Scott McMurray wrote:
Would your average developer know about that sort of thing? I've been using C++ since 1987, and I'd never seen it until a couple months ago. And then only by digging into the Boost.TypeTraits library's source code to figure out how it worked.
Does "your average developer" even write templates that use the extra power than templates offer over generics?
Not sure what you mean, since in C++ "generics" means templates to me. And I don't know how I stack up to the average developer, but I've been writing template code for years and never knew about that.
I'm not convinced that Boost should be all that concerned about developers attempting to write generic code while ignorant of fundamental template building blocks. The trick behind enable_if has been known by the acronym SFINAE since at least 2002, thanks to Vandevoorde and Josuttis's book [1]. Alexandrescu's _Modern C++ Design_ [2] -- containing templates far more complicated than a simple specialization -- was published more than 20 months earlier than that. These are not bleeding-edge or secret techniques.
Ah, that explains it -- most programmers don't buy or read books since the Internet became widely available. I do, but I only go looking for one when I run into a problem, which is likely why I missed those two... I've never run into a problem that only they would have a solution for.
That said, I'm not sure whether it's better to not provide min and max, and thus catch code that uses them without checking is_bounded, or to possibly make it easier to correctly write code that does check is_bounded.
I figured that compiler writers probably knew more about it than I did, and followed their example.
And who knows -- maybe making it easy with SFINAE would mean that those developers that don't know will go looking for the clean way and learn a new tool.
Stranger things have happened. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfe6QACgkQp9x9jeZ9/wRCCQCeLM0JPubKh9DMWPAutCLiHIZe toMAoOxS4jIcIOQeyINhGc6knKEx8aNx =6CL8 -----END PGP SIGNATURE-----

On 3 May 2010 21:43, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
On 05/03/2010 09:22 PM, Scott McMurray wrote:
Does "your average developer" even write templates that use the extra power than templates offer over generics?
Not sure what you mean, since in C++ "generics" means templates to me. And I don't know how I stack up to the average developer, but I've been writing template code for years and never knew about that.
To me, "generics" are like those offered in Java, C#, or SML. The most important difference is that you can specialize templates, and from that you get Turing-completeness.
I figured that compiler writers probably knew more about it than I did, and followed their example.
They may have legacy issues from way back when their compiler didn't support partial template specialization.

on 04.05.2010 at 5:22 Scott McMurray wrote :
That said, I'm not sure whether it's better to not provide min and max, and thus catch code that uses them without checking is_bounded, or to possibly make it easier to correctly write code that does check is_bounded.
a very good point i wish it were said in the standard explicitly
And who knows -- maybe making it easy with SFINAE would mean that those developers that don't know will go looking for the clean way and learn a new tool.
typically a programmer (especially a C++ one) is a very lazy beast so i'm afraid if one encounters a thing he can not understand he'll drop this lib and go for another one which he'd understand better (easier) -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 11:44 AM, DE wrote:
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
i believe that mutating operations are so expensive that the cow overhead becomes negligible and one can live with it unless he is very pedantic
Generally, yes. Incrementing a number is probably the absolute simplest mutating operation possible, so simple that even checking to see whether the integer is unique or not could represent half of the work done. But for any other operation, the copy-on-write overhead is essentially unnoticeable.
and yes, i think that cow is pretty useful here especially complemented by "rvalue&move awareness" also one should take into account that implicit sharing (cow) can be made thread safe with little effort from the author (just a couple of atomic ops) i.e. as soon as atomic lib becomes a part of boost cow implementation of xint can be made thread safe by your (lib user) desire
It can even be thread-safe in its current incarnation, if the user simply calls the _make_unique() function before letting an integer cross thread boundaries. I wouldn't mind eliminating that requirement though.
i'm glad that everyone switched to the implementation because it means there is nothing criminally wrong with the interface said that, we can expect the implementation to become optimal in time so the main work is done i guess congratulations!
Thanks. :-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve/SUACgkQp9x9jeZ9/wRsfQCePTB1dXCbnLMhgwEsPZv/oy7D DmkAn22eAa4YZ8TulDGYmfyWOiSqHxFN =zegF -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 07:39 AM, Stewart, Robert wrote:
If I read your example correctly, then that's about what I was thinking of: algorithms that have to start with a copy of one or more of the passed-in parameters, but then need to modify it/them. The division algorithm requires this, just as one example off the top of my head.
If your algorithm requires a copy, then COW should make it slower because it will first manipulate the reference count and because you must query in each mutating operation whether to make a unique copy.
That depends on how expensive a deep-copy operation is. Making a deep copy of an xint::integer can be a very expensive proposition, compared to just manipulating some pointers, enough to more than offset the overhead of the reference counting stuff. Deep-copying a 2048-bit integer, for example, requires copying something like 76 bytes (the exact number will vary by platform), as well as an allocation. And 2048-bit integers are small for a lot of uses that the library will be put to. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve8rEACgkQp9x9jeZ9/wQgngCfY7y0yAsCHtxyMUfgKgagJip4 VWEAn0gwAbZb+CzDX6WDQZT0wt205LPH =efiz -----END PGP SIGNATURE-----

Chad Nelson wrote:
On 05/02/2010 03:19 AM, Jeffrey Hellrung wrote:
Regarding COW specifically: I'm guessing COW will be a tough sell,
I keep hearing that, but why? It's an internal detail, one that provides (or at least seems to) a very noticeable speed boost under some circumstances, and is disabled when it can't be safely used. Why would anyone, other than developers doing work on the library (i.e. me), care one way or another that the library uses it?
Those reviewing Boost libraries do care about internal details in many cases, as evidenced by the discussion surrounding your library. Furthermore, the usual reaction to COW is to expect low performance in an MT program because it is too often a relic from single threaded design. The typical examples of the benefits of using COW are eliminating the copying overhead of temporaries, which is served today by move semantics and copy elision, and unnecessary copies. The latter merely require discipline to avoid or performance testing to identify. There may be legitimate reason to use COW in your library, but because of the foregoing, you must ensure that you have applied move semantics correctly, write the code properly to avoid unnecessary copies, and prove that COW remains beneficial in a wide range of use cases in a MT test. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 08:04 AM, Stewart, Robert wrote:
[...] There may be legitimate reason to use COW in your library, but because of the foregoing, you must ensure that you have applied move semantics correctly, write the code properly to avoid unnecessary copies, and prove that COW remains beneficial in a wide range of use cases in a MT test.
That's what I'm trying to do. :-) Though I'm open to alternatives, like move semantics. I may have identified something that's slowing down the move implementation in the library, I'll try it today. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve89YACgkQp9x9jeZ9/wTJzgCgux5pqNe5czQD2tAEgous0DF/ Nn0AoISXjIjw35Qf30mLeF4lqmjvEmzK =zijU -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 02:44 AM, joel falcou wrote:
If you're saying that people often write multithreaded programs, then I have to disagree. In my experience, it's rare, and most programmers actively avoid them.
Plural of anedocte is not data. In genral, not taking multithreading seriously now is likely to be a problem in the upcoming years.
I thought I *was* taking it seriously. I'm providing a way to support it, after all. :-)
Then it means you did somethign wrong or the code doesn't lend itself to trivial multithreading ...
Sorry for the tone of that, I wasn't implying anything wrong with yourself, just that this kind of result (multithreaded version being slower) is usually because soemthing don't lend itself to be multithreaded. Do you have this MT code somewhere still, i may have a look if needed.
All of the code is available in the Boost Sandbox <https://svn.boost.org/svn/boost/sandbox/xint> and Vault <http://www.boostpro.com/vault/index.php?action=downloadfile&filename=xint.zip&directory=&>. There are only two (well, three now) things that change when switching to the thread-safe version: integers aren't allowed to use copy-on-write, access to the random number generator is serialized, and (now) Boost.Move semantics are enabled. I've been assuming that the copy-on-write was responsible for the major part of the speed difference, but after thinking about it, that doesn't make a lot of sense. The serialized access to the random number generator could be responsible for a good part of it. The tests I based that assumption on used it heavily. I'll run some further tests when I have a chance today to see how they turn out. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdkxcACgkQp9x9jeZ9/wQ8VQCeNivTi3WQMZU0+m5uMSx5su+s 1uUAoKOhdtuTS3EAKj/364amZ/ZPHD+M =hDR/ -----END PGP SIGNATURE-----

On 2 May 2010 10:58, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
I've been assuming that the copy-on-write was responsible for the major part of the speed difference, but after thinking about it, that doesn't make a lot of sense. The serialized access to the random number generator could be responsible for a good part of it. The tests I based that assumption on used it heavily. I'll run some further tests when I have a chance today to see how they turn out.
Why do you have a global random number generator at all? Boost.Random doesn't provide one, so I don't see why you should either.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 12:37 PM, Scott McMurray wrote:
I've been assuming that the copy-on-write was responsible for the major part of the speed difference, but after thinking about it, that doesn't make a lot of sense. The serialized access to the random number generator could be responsible for a good part of it. The tests I based that assumption on used it heavily. I'll run some further tests when I have a chance today to see how they turn out.
Why do you have a global random number generator at all?
Because I hadn't thought about an alternative until you said this. :-)
Boost.Random doesn't provide one, so I don't see why you should either.
It *would* simplify things greatly for me. I'm just concerned that it might make things more difficult for someone who just wants to use the library for a quick one-off test. My goal is, as much as possible, to stay out of the way of the person using the library -- for that, having a default "good enough" random generator is pretty much a necessity. (The use-case I'm basing that on: When I'm trying to solve a problem, and go hunting for a tool that I need to do it, it's frustrating to have to spend a lot of time learning how to set up the tool -- I just want something that I can quickly use to solve the problem at hand. Later, when I'm not so focused on a specific problem, I'll gladly dig into the documentation and figure out the non-default features that I might find a future use for.) Maybe if I had a random number generator as a parameter, defaulting to an internal global one that is deliberately *not* thread-safe, and simply documented that if you use it from multiple threads, you're responsible for either serializing the access or providing your own generators...? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdtMsACgkQp9x9jeZ9/wSR0gCeNZ1DAFzFnmz9SPT7dmvgw3/Y /cIAoMmZQFMWfxLTQBQSW9Okerxsdz7f =qEQ6 -----END PGP SIGNATURE-----

On 2 May 2010 13:22, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
It *would* simplify things greatly for me. I'm just concerned that it might make things more difficult for someone who just wants to use the library for a quick one-off test. My goal is, as much as possible, to stay out of the way of the person using the library -- for that, having a default "good enough" random generator is pretty much a necessity.
How about, then, you just provide a boost::xint::default_random_generator type (or typedef)? Users can then create a global instance for their simple testing needs. In my experience I usually end up wrapping the generator for the specific use anyways, so the code difference is tiny.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 01:36 PM, Scott McMurray wrote:
It *would* simplify things greatly for me. I'm just concerned that it might make things more difficult for someone who just wants to use the library for a quick one-off test. My goal is, as much as possible, to stay out of the way of the person using the library -- for that, having a default "good enough" random generator is pretty much a necessity.
How about, then, you just provide a boost::xint::default_random_generator type (or typedef)? Users can then create a global instance for their simple testing needs. In my experience I usually end up wrapping the generator for the specific use anyways, so the code difference is tiny.
Sorry, but I'm confused. How would that be different from what the library is doing now? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdvRMACgkQp9x9jeZ9/wQ90QCgge5DtLXcfHH7IEqJAn5+DWki mKUAoNJHmjTrC7/Afhhc/6S5jTYRRvke =ZeA/ -----END PGP SIGNATURE-----

On 2 May 2010 13:57, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
Sorry, but I'm confused. How would that be different from what the library is doing now?
Semantically? It wouldn't. It just means you're leaving the thread safety choices up to the user by providing the same guarantees that just about every type in the standard and boost offer: Independent instances can be used independently, shared instances need mutex. Leave it up to the user whether they want thread-specific random, mutexed random, task-queue-controlled random, whatever.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 02:06 PM, Scott McMurray wrote:
Sorry, but I'm confused. How would that be different from what the library is doing now?
Semantically? It wouldn't. It just means you're leaving the thread safety choices up to the user by providing the same guarantees that just about every type in the standard and boost offer: Independent instances can be used independently, shared instances need mutex.
Leave it up to the user whether they want thread-specific random, mutexed random, task-queue-controlled random, whatever.
Sorry again, but I wasn't just asking about semantics -- I'm asking what you're suggesting the actual code should look like. I'm going through a function at least partly so that I can wrap the provided random generator to provide the unsigned int type that my code is expecting, regardless of what type or size the generator is defined to return, without overly complicating things for the user of the library. Look at the definition of detail::random_generator in random.hpp to see what I mean. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdw+YACgkQp9x9jeZ9/wRLjQCfcyJUVxgCTMmWoHjlgcj9WNdD c9EAoL/tdJE7qTN11srUv/tRMrqBXXp2 =vPon -----END PGP SIGNATURE-----

On 2 May 2010 14:26, Chad Nelson <chad.thecomfychair@gmail.com> wrote:
Sorry again, but I wasn't just asking about semantics -- I'm asking what you're suggesting the actual code should look like. I'm going through a function at least partly so that I can wrap the provided random generator to provide the unsigned int type that my code is expecting, regardless of what type or size the generator is defined to return, without overly complicating things for the user of the library. Look at the definition of detail::random_generator in random.hpp to see what I mean.
Are you inventing a new method here? It seems like there's no need for you to define anything new that models the NumberGenerator concept (or any of the concepts derived rom that), since there are plenty already <http://www.boost.org/doc/libs/1_42_0/libs/random/random-generators.html>. So to fit in the Boost.Random model, you should be providing a new model of the RandomDistribution concept for generating random primes. Hopefully your integer class will also work with the uniform_int <http://www.boost.org/doc/libs/1_42_0/libs/random/random-distributions.html#uniform_int> distribution, and I'd claim that if it doesn't, that's a bug in either Boost.Random or your library. Then the user with use a variate_generator <http://www.boost.org/doc/libs/1_42_0/libs/random/random-variate.html> with appropriate template arguments to get what they want. My suggestion of the default_random_generator would simply be a typedef to a usual set of these arguments, so people could instantiate one without needing to know the details, and could then use it like they're already used to with existing Boost.Random generators. ~ Scott (who was hopefully clearer that time)

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 03:14 PM, Scott McMurray wrote:
Sorry again, but I wasn't just asking about semantics -- I'm asking what you're suggesting the actual code should look like. I'm going through a function at least partly so that I can wrap the provided random generator to provide the unsigned int type that my code is expecting, regardless of what type or size the generator is defined to return, without overly complicating things for the user of the library. Look at the definition of detail::random_generator in random.hpp to see what I mean.
Are you inventing a new method here?
Not that I'm aware of, just using Boost.Random as it seems to be intended.
It seems like there's no need for you to define anything new that models the NumberGenerator concept (or any of the concepts derived rom that), since there are plenty already <http://www.boost.org/doc/libs/1_42_0/libs/random/random-generators.html>.
Yes, and you can plug any one of those into XInt's current random number system. It uses a mersenne_twister by default, since there are currently no secure random number generators usable in Windows in Boost.Random (though the release currently being prepped is supposed to have one).
So to fit in the Boost.Random model, you should be providing a new model of the RandomDistribution concept for generating random primes.
You lost me. I'm not sure that the Boost.Random model even *could* be adapted to use large integers (and haven't looked), but in any case, that's not my intent. The random number system in XInt is designed primarily and specifically for providing large random numbers for the random_prime function, and secondarily to get numbers for the purpose of testing the library. It has features that aren't really applicable to a generic random number generator.
Hopefully your integer class will also work with the uniform_int <http://www.boost.org/doc/libs/1_42_0/libs/random/random-distributions.html#uniform_int> distribution, and I'd claim that if it doesn't, that's a bug in either Boost.Random or your library.
XInt uses the uniform_int distribution -- again, see the detail::random_generator class in random.hpp. And if Boost.Random can use a user-defined type, then I'm sure someone could hook them together without much effort to make a generic large-integer random generator. That's not my goal, I just need a decent source of entropy so that I can build some large random numbers for the purposes I outlined above.
Then the user with use a variate_generator <http://www.boost.org/doc/libs/1_42_0/libs/random/random-variate.html> with appropriate template arguments to get what they want. My suggestion of the default_random_generator would simply be a typedef to a usual set of these arguments, so people could instantiate one without needing to know the details, and could then use it like they're already used to with existing Boost.Random generators.
Ah... the light dawns. :-) I think I see what you're saying now, vaguely. Yes, that might be simple enough that people could whip something up without much study time. I'll see what I can come up with. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvd2WoACgkQp9x9jeZ9/wS5sQCfa4PxRC/kMvkOKdL2RpN9GZkZ hC8AniBhChbVxalFxTiXbkIH/fjUx3sb =64Qr -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 8:27 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 02:08 PM, Marius Stoica wrote: I'm sorry to say that my opinion differs. If someone is evaluating the library against several others to see which one he wants to use, he's not likely to dig into the documentation to figure out how to get the best speed out of it -- he's going to compare the default configurations. I'd like XInt to still be in the running when he does.
Also, multithreaded operation is still fairly uncommon. I'd hate to make everyone pay for something that only a few need, especially when the speed cost is so high (the single-threaded version is *twice* the speed of the multithreaded one).
There are context on which your conditial compilation option makes everyone pay for something that only a few need. If I have an application on which there are some parts that need thread safety on your library and all the others don't need it all the other parts are paying for a few. To satisfy everybody you need to probide both. If your library is header only, it is enough to provide two classes in separated files. If your libary need to be built, as I proposed already, you need to provide two libs. Best, Vicente

On Saturday 01 May 2010 21:27:43 Chad Nelson wrote:
On 05/01/2010 02:08 PM, Marius Stoica wrote:
That would simplify things a great deal. I've never tried it though... an extra 130K of headers in every source code file that uses the library is a little much, isn't it?
I don't think that's an issue. Most(almost all) of that code is conditionally compiled and the final size of what would end up in a binnary will be very small.
It's still code that would have to be read and parsed for every compilation unit that includes it. Computers are a lot faster these days than when I learned to program, but that's still enough to make me think twice before doing something like that.
Also let me check some of the other libraries in boost.
Here in alphabethic order (Afaict all of these are header only) accumulators - 506k algoritm - 305k archive - 395k asio - 1.5MiB assign - 95k bitmap - 488k bind - 177k
I've used a few of those, and haven't noticed a major compile-speed problem, which is an argument in your favor.
Dunno if you notticed but i was just checking the first boost libraries in alphabethic order. I guess what i was trying to say is that pretty much all the boost libraries are like this. It's ... tradition :) Also i'm not certain the headers need to be parsed every time anyway. Most compiler support precompiled headers. If compilation speed becomes too much of an issue I'm sure they'll become more widely used.
Also because ubuntu screwed up their boost doesn't mean that all distros will. The default compiled behaviour should be the one that works in all cases not the one that's faster imho.
I'm sorry to say that my opinion differs. If someone is evaluating the library against several others to see which one he wants to use, he's not likely to dig into the documentation to figure out how to get the best speed out of it -- he's going to compare the default configurations. I'd like XInt to still be in the running when he does.
That's certainly a good point since i've seen software getting a reputation for being slow and not being able to change that reputation despite seriously improving in performance.(postgresql)
Also, multithreaded operation is still fairly uncommon. I'd hate to make everyone pay for something that only a few need, especially when the speed cost is so high (the single-threaded version is *twice* the speed of the multithreaded one).
How did you managed to get that difference anyway since threads are just processes without the memory protection. C++11 will add several things related to this including thread local storage , move and others. Do you expect that with this the difference will dissapear? If so i think it's best to support this with a compile flag since that can be easily deprecated.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 09:49 AM, Marius Stoica wrote:
I've used a few of those, and haven't noticed a major compile-speed problem, which is an argument in your favor.
Dunno if you notticed but i was just checking the first boost libraries in alphabethic order. I guess what i was trying to say is that pretty much all the boost libraries are like this. It's ... tradition :)
Just not a tradition that I've personally experimented with. :-)
Also i'm not certain the headers need to be parsed every time anyway. Most compiler support precompiled headers. If compilation speed becomes too much of an issue I'm sure they'll become more widely used.
Another good point.
Also, multithreaded operation is still fairly uncommon. I'd hate to make everyone pay for something that only a few need, especially when the speed cost is so high (the single-threaded version is *twice* the speed of the multithreaded one).
How did you managed to get that difference anyway since threads are just processes without the memory protection.
Copy-on-write. Though please see my reply to Joel Falcou this morning; I may have misinterpreted the results. I'll test that later today, when I have some free time.
C++11 will add several things related to this including thread local storage , move and others. Do you expect that with this the difference will dissapear?
It's quite possible. Copy-on-write is still measurably faster than emulated move semantics via Boost.Move, but built-in ones could very well erase that difference.
If so i think it's best to support this with a compile flag since that can be easily deprecated.
That's how I'm doing it now. :-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdrvYACgkQp9x9jeZ9/wSLhwCgzHVd7qb5Wjwp11UVWAs873d2 jB0An3gW90OfCio58ZxPN9TiWxniidUk =N7yJ -----END PGP SIGNATURE-----

On Sunday 02 May 2010 19:57:27 Chad Nelson wrote:
It's quite possible. Copy-on-write is still measurably faster than emulated move semantics via Boost.Move, but built-in ones could very well erase that difference.
Why don't you test ? Gcc supports rvalue references since 4.3 http://gcc.gnu.org/projects/cxx0x.html the link there to library features suggests that move is implemented

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 02:41 PM, Marius Stoica wrote:
It's quite possible. Copy-on-write is still measurably faster than emulated move semantics via Boost.Move, but built-in ones could very well erase that difference.
Why don't you test ? Gcc supports rvalue references since 4.3
I didn't realize that. I'll add that to my list of tests to run today, thanks. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdvcQACgkQp9x9jeZ9/wTQsQCeKRfd4DfLxQFXVQ9ohx4UWKJ6 cuQAoO8iKxpzlC/wHG75FovOPJqD1JBv =GlYu -----END PGP SIGNATURE-----

on 30.04.2010 at 9:35 Chad Nelson wrote :
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...] Please take a look and let me know what you think of the changes. I'm very happy with them.
well i tried to lay my emotions aside and inspect the lib itself i must say however that the docs are very clear and tell about the library almost all i want to know there are wise words there indeed (e.g. on rationale page) so i think that the design of the library is _perfect_ (yeah, yeah, i know that there is always room for improvements...) beside other things i understand why you did things this way and not the other way however so far i have a suggestion about fixed_integer for me it is counter intuitive that a fixed_integer<N> allocates memory on the heap rather than on the stack i suggest to reserve storage for data in a static array like char fixed_data[sizeof(data_t) + n]; then setting a pointer to data_t (defined in base_integer) like data = static_cast<data_t*>(fixed_data); and then initializing it as usual classes are not polymorphic and slicing is not intended in other words the most derived class is responsible for memory management so if a necessity appears to allocate different storage it can be correctly freed on destruction like ~fixed_integer() { if (this->data && this->data!=this->fixed_data) deallocate(data); } this way you don't need to rewrite everything and you get rid of costly allocation in case you say that data allocated on the heap makes implicit sharing possible i'd say that copying of reasonable size fixed ints beats allocations in the end i hope i got everything right in the implementation and all this doesn't sound like nonsense anyway i hope you got the main idea oh and one more suggestion when you define a variable that is not meant to be modified declare it const it immediately provides information to a reader and also compiler ensures your intention -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 04/30/2010 05:02 PM, DE wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
well i tried to lay my emotions aside and inspect the lib itself
i must say however that the docs are very clear and tell about the library almost all i want to know there are wise words there indeed (e.g. on rationale page)
:-)
so i think that the design of the library is _perfect_ (yeah, yeah, i know that there is always room for improvements...) beside other things i understand why you did things this way and not the other way
I tried to convey them.
however so far i have a suggestion about fixed_integer for me it is counter intuitive that a fixed_integer<N> allocates memory on the heap rather than on the stack [...]
That was a tough decision. I started out with it on the heap, but there's no way to use the more-efficient swap(), operator=, or copy/move constructors that way. The best choice came down to which set of operations happens more commonly: swapping and assignment or creating a new object. I have no way of objectively measuring that for other people's code, but for my own, swapping and assignment edge out object creation, slightly.
classes are not polymorphic and slicing is not intended in other words the most derived class is responsible for memory management so if a necessity appears to allocate different storage it can be correctly freed on destruction like
~fixed_integer() { if (this->data && this->data!=this->fixed_data) deallocate(data); }
Yes, that's the design I used for the "quick digits" in the earlier version of the library.
this way you don't need to rewrite everything and you get rid of costly allocation in case you say that data allocated on the heap makes implicit sharing possible i'd say that copying of reasonable size fixed ints beats allocations in the end
Since the data for a fixed_integer will always be the same size, the implementation could re-use older allocations instead of deallocating them and allocating new ones. I can see a fairly easy way to do that, and give the user control over what's being held if he wants it. Would that address your concern?
i hope i got everything right in the implementation and all this doesn't sound like nonsense anyway i hope you got the main idea
I think I did. :-)
oh and one more suggestion when you define a variable that is not meant to be modified declare it const it immediately provides information to a reader and also compiler ensures your intention
Did I miss one? Other than possibly the zerodata stuff, I can't think of any that should be const but aren't. Hm, maybe some POD types in the internals...? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvbVT4ACgkQp9x9jeZ9/wR+HACg6wky+AGMlYfQvHsy9mrHf1Ii o8AAoINaoU31GWBlAIQNKiPpBwZJlKy8 =H72T -----END PGP SIGNATURE-----

on 01.05.2010 at 2:10 Chad Nelson wrote :
however so far i have a suggestion about fixed_integer for me it is counter intuitive that a fixed_integer<N> allocates memory on the heap rather than on the stack [...]
That was a tough decision. I started out with it on the heap, but there's no way to use the more-efficient swap(), operator=, or copy/move constructors that way. The best choice came down to which set of operations happens more commonly: swapping and assignment or creating a new object. I have no way of objectively measuring that for other people's code, but for my own, swapping and assignment edge out object creation, slightly.
that argument is enough for me and anyway it's _your_ decision i only make a suggestion ...
this way you don't need to rewrite everything and you get rid of costly allocation in case you say that data allocated on the heap makes implicit sharing possible i'd say that copying of reasonable size fixed ints beats allocations in the end
Since the data for a fixed_integer will always be the same size, the implementation could re-use older allocations instead of deallocating them and allocating new ones. I can see a fairly easy way to do that, and give the user control over what's being held if he wants it. Would that address your concern?
pretty much
oh and one more suggestion when you define a variable that is not meant to be modified declare it const it immediately provides information to a reader and also compiler ensures your intention
Did I miss one? Other than possibly the zerodata stuff, I can't think of any that should be const but aren't. Hm, maybe some POD types in the internals...?
i meant this: in the followng code (monty.cpp) 00033 digit_t inverse0(const integer& n) { 00034 // Using the Duss and Kalisk simplification 00035 doubledigit_t x = 2, y = 1; 00036 digit_t n0 = n._get_digit(0); 00037 for (size_t i = 2; i <= bits_per_digit; ++i, x <<= 1) 00038 if (x < ((n0 * y) & ((x << 1) - 1))) 00039 y += x; 00040 return digit_t(x - y); 00041 } the variable 'n0' is not modified so it actually is const (and should be declared such) 'x' is not modified in this piece as well this is a minor issue and concerns style of coding so it is arguable by definition however scott meyers, andrei alexandrescu and herb sutter recommend to make everything const unless it must be modifyed so you might want to decide to follow this recommendation ...or not -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "DE" <satan66613@yandex.ru> To: "Chad Nelson" <boost@lists.boost.org> Sent: Saturday, May 01, 2010 6:43 PM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review
on 01.05.2010 at 2:10 Chad Nelson wrote :
however so far i have a suggestion about fixed_integer for me it is counter intuitive that a fixed_integer<N> allocates memory on the heap rather than on the stack [...]
That was a tough decision. I started out with it on the heap, but there's no way to use the more-efficient swap(), operator=, or copy/move constructors that way. The best choice came down to which set of operations happens more commonly: swapping and assignment or creating a new object. I have no way of objectively measuring that for other people's code, but for my own, swapping and assignment edge out object creation, slightly.
that argument is enough for me and anyway it's _your_ decision i only make a suggestion
What about implementing both strategies, either as separated classes, or adding a template parameter? Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 01:01 PM, vicente.botet wrote:
however so far i have a suggestion about fixed_integer for me it is counter intuitive that a fixed_integer<N> allocates memory on the heap rather than on the stack [...]
That was a tough decision. I started out with it on the heap, but there's no way to use the more-efficient swap(), operator=, or copy/move constructors that way. The best choice came down to which set of operations happens more commonly: swapping and assignment or creating a new object. I have no way of objectively measuring that for other people's code, but for my own, swapping and assignment edge out object creation, slightly.
that argument is enough for me and anyway it's _your_ decision i only make a suggestion
What about implementing both strategies, either as separated classes, or adding a template parameter?
It could be done with separated classes, but I don't see any way to do it with a template parameter; the array would have to be included in the class itself if it was ever going to be used, and I don't know of any way to eliminate it via a template parameter. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcbU0ACgkQp9x9jeZ9/wRigQCg3ydTh/2cDLvWIw1RMtvc8d7Y yuoAoIAu4GaPOgNEQNvQCpYCw/IXWPGC =/3mM -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 8:05 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 01:01 PM, vicente.botet wrote:
however so far i have a suggestion about fixed_integer for me it is counter intuitive that a fixed_integer<N> allocates memory on the heap rather than on the stack [...]
That was a tough decision. I started out with it on the heap, but there's no way to use the more-efficient swap(), operator=, or copy/move constructors that way. The best choice came down to which set of operations happens more commonly: swapping and assignment or creating a new object. I have no way of objectively measuring that for other people's code, but for my own, swapping and assignment edge out object creation, slightly.
that argument is enough for me and anyway it's _your_ decision i only make a suggestion
What about implementing both strategies, either as separated classes, or adding a template parameter?
It could be done with separated classes, but I don't see any way to do it with a template parameter; the array would have to be included in the class itself if it was ever going to be used, and I don't know of any way to eliminate it via a template parameter.
With an addition template parameter you can for example specialize template <std::size_t N, bool HeapAllocated> class fixed_integer; template <std::size_t N> class fixed_integer<N, true> ... // your current implementation template <std::size_t N> class fixed_integer<N, false> ... // implementation suggested by Pavel Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 02:44 PM, vicente.botet wrote:
What about implementing both strategies, either as separated classes, or adding a template parameter?
It could be done with separated classes, but I don't see any way to do it with a template parameter; the array would have to be included in the class itself if it was ever going to be used, and I don't know of any way to eliminate it via a template parameter.
With an addition template parameter you can for example specialize [...]
Ah, I see... I hadn't considered that possibility. Thanks for the information. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcn/0ACgkQp9x9jeZ9/wRM5QCgg6gmjJoVOta6eA0RfYKA5gES pYQAoNDi/KFk9TdtvCS9AKtowu27kHbv =2j1+ -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 12:43 PM, DE wrote:
this way you don't need to rewrite everything and you get rid of costly allocation in case you say that data allocated on the heap makes implicit sharing possible i'd say that copying of reasonable size fixed ints beats allocations in the end
Since the data for a fixed_integer will always be the same size, the implementation could re-use older allocations instead of deallocating them and allocating new ones. I can see a fairly easy way to do that, and give the user control over what's being held if he wants it. Would that address your concern?
pretty much
Then I'll put it on the to-do list for the next release. I'd probably have done it for this one, if I'd thought of it.
oh and one more suggestion when you define a variable that is not meant to be modified declare it const it immediately provides information to a reader and also compiler ensures your intention
Did I miss one? Other than possibly the zerodata stuff, I can't think of any that should be const but aren't. Hm, maybe some POD types in the internals...?
i meant this: in the followng code (monty.cpp)
00033 digit_t inverse0(const integer& n) { 00034 // Using the Duss and Kalisk simplification 00035 doubledigit_t x = 2, y = 1; 00036 digit_t n0 = n._get_digit(0); 00037 for (size_t i = 2; i <= bits_per_digit; ++i, x <<= 1) 00038 if (x < ((n0 * y) & ((x << 1) - 1))) 00039 y += x; 00040 return digit_t(x - y); 00041 }
Ah, I see. POD types in the internals. :-)
the variable 'n0' is not modified so it actually is const (and should be declared such) 'x' is not modified in this piece as well
(It's modified -- look at the end of the "for" line.)
this is a minor issue and concerns style of coding so it is arguable by definition however scott meyers, andrei alexandrescu and herb sutter recommend to make everything const unless it must be modifyed so you might want to decide to follow this recommendation ...or not
It sounds like a good practice. It would be useful to catch some typos at compile-time, where you use one variable but meant to use a different one (something I've done on occasion). And as you said, it does make code more readable, so I'll try to adopt now that I know about it. But since the compiled code will be identical either way, for POD types, I don't think it warrants combing through the code to correct violations of it. I'll change them when I find them during refactoring. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcazMACgkQp9x9jeZ9/wRWOwCfdV0ADlK/39w1cpKK2oPG7gvJ am0AnRo0SltrbLE/bDi8m9zDQWATZCw4 =S+Qt -----END PGP SIGNATURE-----

on 01.05.2010 at 21:56 Chad Nelson wrote :
i meant this: in the followng code (monty.cpp)
00033 digit_t inverse0(const integer& n) { 00034 // Using the Duss and Kalisk simplification 00035 doubledigit_t x = 2, y = 1; 00036 digit_t n0 = n._get_digit(0); 00037 for (size_t i = 2; i <= bits_per_digit; ++i, x <<= 1) 00038 if (x < ((n0 * y) & ((x << 1) - 1))) 00039 y += x; 00040 return digit_t(x - y); 00041 }
Ah, I see. POD types in the internals. :-)
not only pod types but any types
the variable 'n0' is not modified so it actually is const (and should be declared such) 'x' is not modified in this piece as well
(It's modified -- look at the end of the "for" line.)
my bad, sorry
this is a minor issue and concerns style of coding so it is arguable by definition however scott meyers, andrei alexandrescu and herb sutter recommend to make everything const unless it must be modifyed so you might want to decide to follow this recommendation ...or not
It sounds like a good practice. It would be useful to catch some typos at compile-time, where you use one variable but meant to use a different one (something I've done on occasion). And as you said, it does make code more readable, so I'll try to adopt now that I know about it.
But since the compiled code will be identical either way, for POD types, I don't think it warrants combing through the code to correct violations of it. I'll change them when I find them during refactoring.
you've got it absolutely right -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Friday, April 30, 2010 7:35 AM Subject: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault.
This is a major overhaul of the library, taking into account all of the feedback and recommendations provided on the first two:
* The exception-blocking system is gone, replaced by a separate nothrow_integer class.
* There's now a fixed_integer class template as well.
* The test functions now use Boost.Test, and the documentation has been moved to Doxygen.
* Nearly every function received a thorough examination as well; many of them were tweaked, and a few completely replaced.
Please take a look and let me know what you think of the changes. I'm very happy with them.
Hi, you forget to say in the documentation that your library needs to be built and included on the user program. Ths is inportant to know for a lot of people. "How do I use it? That's the best part. If you've installed or compiled the Boost library already, all you need to do is add #include <boost/xint/xint.hpp> at the top of your source code file and declare your variable as type boost::xint::integer." Best, _____________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Friday, April 30, 2010 7:35 AM Subject: [boost] [xint] Third release is ready, requesting preliminary review
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault.
This is a major overhaul of the library, taking into account all of the feedback and recommendations provided on the first two:
* The test functions now use Boost.Test, and the documentation has been moved to Doxygen.
One of the probels with Doxygen is that by default all the details are included also. I would preferend a documentation on which the xint::detail and the classes , function , .. included in do not appear in the doc. I'm sure that this is possible, and that this will let the user concentrate on what is important for her/him. Best, _________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/

----- Original Message ----- From: "vicente.botet" <vicente.botet@wanadoo.fr> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 11:32 AM Subject: Re: [boost] [xint] Third release is ready,requesting preliminary review ----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Friday, April 30, 2010 7:35 AM Subject: [boost] [xint] Third release is ready, requesting preliminary review
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault.
This is a major overhaul of the library, taking into account all of the feedback and recommendations provided on the first two:
* The test functions now use Boost.Test, and the documentation has been moved to Doxygen.
One of the probels with Doxygen is that by default all the details are included also. I would preferend a documentation on which the xint::detail and the classes , function , .. included in do not appear in the doc. I'm sure that this is possible, and that this will let the user concentrate on what is important for her/him. Best, _________________ Vicente Juan Botet Escribá http://viboes.blogspot.com/ _______________________________________________ Ah, and please don't generate documentation for the private class members. Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 05:45 AM, vicente.botet wrote:
Ah, and please don't generate documentation for the private class members.
I thought I'd told Doxygen to ignore private members... yes, I did. Did you find some anyway? If so, where? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcSK0ACgkQp9x9jeZ9/wShjQCeP2a6ZaYXa2yrxQMBCOmFK5jI RNMAoNsJCOBF3G/o2MOm0ZlRbzBSVPA+ =kang -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 5:28 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 05:45 AM, vicente.botet wrote:
Ah, and please don't generate documentation for the private class members.
I thought I'd told Doxygen to ignore private members... yes, I did. Did you find some anyway? If so, where?
My bad. I was confussed with the following internal functions, that let me thought that they were private :( Public Member Functions ~base_integer () Internal Functions void _add (const base_integer &n) void _attach (const base_integer ©) void _cleanup () Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 11:35 AM, vicente.botet wrote:
Ah, and please don't generate documentation for the private class members.
I thought I'd told Doxygen to ignore private members... yes, I did. Did you find some anyway? If so, where?
My bad. I was confussed with the following internal functions, that let me thought that they were private :( [...]
Ah, I see. I believe all of those are in the detail namespace, so they'll go away when I remove that namespace from the documentation, as you suggested earlier. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcTJwACgkQp9x9jeZ9/wTtngCg3abviydGGQk2Eanbft9Omuz1 lC8AoMAQTtHWh3oxnOaAGzAbpFuRgS1R =Begw -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 05:32 AM, vicente.botet wrote:
One of the probels with Doxygen is that by default all the details are included also. I would preferend a documentation on which the xint::detail and the classes , function , .. included in do not appear in the doc. I'm sure that this is possible, and that this will let the user concentrate on what is important for her/him.
Easily done; I've put it on my to-do list for the next release. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcR/MACgkQp9x9jeZ9/wQ7JACgnp9c40ZEQ/buSZGqbEvsE1tL L8AAnR/L+O8NIFelrG4tdc4GuBckCfXf =sReV -----END PGP SIGNATURE-----

----- Original Message ----- From: "Chad Nelson" <chad.thecomfychair@gmail.com> To: <boost@lists.boost.org> Sent: Saturday, May 01, 2010 5:25 PM Subject: Re: [boost] [xint] Third release is ready, requesting preliminary review
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 05/01/2010 05:32 AM, vicente.botet wrote:
One of the probels with Doxygen is that by default all the details are included also. I would preferend a documentation on which the xint::detail and the classes , function , .. included in do not appear in the doc. I'm sure that this is possible, and that this will let the user concentrate on what is important for her/him.
Easily done; I've put it on my to-do list for the next release.
As you inherits from some classes in the detail namespace don't forget to document the members inherited. Is Doxygen able to do this automaticaly? Best, Vicente

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/01/2010 11:36 AM, vicente.botet wrote:
One of the probels with Doxygen is that by default all the details are included also. I would preferend a documentation on which the xint::detail and the classes , function , .. included in do not appear in the doc. I'm sure that this is possible, and that this will let the user concentrate on what is important for her/him.
Easily done; I've put it on my to-do list for the next release.
As you inherits from some classes in the detail namespace don't forget to document the members inherited. Is Doxygen able to do this automaticaly?
I don't know whether it can do that automatically, but I think I can manually tell it to ignore those. I'll look into it. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvcTXAACgkQp9x9jeZ9/wQLWQCgnycC4sBkbP4Y2dNjXtjvcTCv i2UAoMSSECAfuxUGb4M5T8o2i6psEhD4 =DNCw -----END PGP SIGNATURE-----

On 4/29/2010 10:35 PM, Chad Nelson wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
I agree with the design to have the "default" class throw exceptions, and also to have a no-throw variant. Your rationale section is a very good section to have, given the differing opinions among "us all" ;) Also, the support for -0 is about how I'd imagine it, tucked away somewhere you'd never notice it except if you really wanted to know. For now, just a few comments/questions on complexity. It appears your complexities are formulated in terms of "n", but this (I hope!) is not the same "n" as the input parameter (e.g., I certainly hope that multiplying together integers n and m is not Theta(n*m) complexity!). Although one could guess what you really mean (n = # of chunks, or whatever), you should be more precise. You also, to more precise, might want to use "Big-Theta" notation rather than "Big-Oh", where you can (it might be that, for example, multiplication is optimized to be constant-time if either argument is "1", though if that's the case, you might want to mention that). Referring to your "A Note on Algorithmic Complexity": Which algorithms are you making an "educated guess" on their complexity? I'm curious: Are you researching, or do you have plans to research, more efficient multiplication algorithms (Karatsuba's, FFT-based, etc.)? I believe these only become efficient at large integers, but I'm not sure how large... Okay, some questions regarding the arithmetic functions: It looks like you have named free functions for all the arithmetic operators which have identical functionality to the overloaded arithmetic operators. This was obviously deliberate. Can you comment on this decision, i.e., why have the named free functions at all? Do you have free functions that implement the low-level arithmetic operations for just pairs of pointers? E.g., do you have an add function that looks like void add( const unsigned int* x_first, const unsigned int* x_last, const unsigned int* y_first, const unsigned int* y_last, const unsigned int* result_first); ? Okay this signature is probably not what you'd want, but more fundamentally my question is, have you separated the arithmetic/numeric algorithms from the memory management algorithms? Can one build their own, e.g., stack-based integer class as just a wrapper around the arithmetic algorithms? Also, I don't see any allocator template parameters anywhere. I'm guessing any consideration of acceptance into boost is conditional on allocator support. Very nice work on the documentation. I'll have to continue to troll through it at my usually leisurely pace. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 03:48 AM, Jeffrey Lee Hellrung, Jr. wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault. [...]
I agree with the design to have the "default" class throw exceptions, and also to have a no-throw variant. Your rationale section is a very good section to have, given the differing opinions among "us all" ;)
So I figured. :-)
Also, the support for -0 is about how I'd imagine it, tucked away somewhere you'd never notice it except if you really wanted to know.
As we discussed.
For now, just a few comments/questions on complexity. It appears your complexities are formulated in terms of "n", but this (I hope!) is not the same "n" as the input parameter (e.g., I certainly hope that multiplying together integers n and m is not Theta(n*m) complexity!).
:-)
Although one could guess what you really mean (n = # of chunks, or whatever), you should be more precise.
Easy enough... done. That paragraph of the complexity page now reads: "This documentation includes a time-complexity estimate, in big-O notation, for each algorithm. The n in the complexity estimates is roughly the number of bits in the parameter(s). (More accurately, it's the number of digit_t values needed to hold those bits.)"
You also, to more precise, might want to use "Big-Theta" notation rather than "Big-Oh", where you can
I'm not familiar with Big-Theta. I've just looked it up, but I think I must be missing some background information because it doesn't make a lot of sense.
(it might be that, for example, multiplication is optimized to be constant-time if either argument is "1", though if that's the case, you might want to mention that).
I check for zero, but not one. I didn't think it was worth mentioning details like that... the complexity estimate is just something to give people some idea how the time will increase based on the size of the parameters.
Referring to your "A Note on Algorithmic Complexity": Which algorithms are you making an "educated guess" on their complexity?
The ones that gave me the most trouble were the three based on the GCD algorithm (gcd, lcm, and invmod, I believe). I finally found a research paper describing the complexity of the binary GCD algorithm, and I based the other two on that.
I'm curious: Are you researching, or do you have plans to research, more efficient multiplication algorithms (Karatsuba's, FFT-based, etc.)? I believe these only become efficient at large integers, but I'm not sure how large...
Yes, I already have a description of the Karatsuba one to work from, for a later release. It's supposed to be more effective than the traditional version once you get past a certain size, but I don't know what that size is yet. Once that's added, I'll look into the others.
Okay, some questions regarding the arithmetic functions: It looks like you have named free functions for all the arithmetic operators which have identical functionality to the overloaded arithmetic operators. This was obviously deliberate. Can you comment on this decision, i.e., why have the named free functions at all?
Originally those were the functions that handled the internals. I had to move the internals down by another layer of abstraction in order to efficiently handle the fixed_integer types, and I just never thought to remove the free functions.
Do you have free functions that implement the low-level arithmetic operations for just pairs of pointers? [...]
Not pairs of pointers, but I do have lower-level functions (the ones in the detail namespace) that work on base_integer types.
? Okay this signature is probably not what you'd want, but
[...] more fundamentally my question is, have you separated the arithmetic/numeric algorithms from the memory management algorithms?
They're separated, in that the memory management is all done by the base_integer class, and the math is handled by the higher classes and free functions.
Can one build their own, e.g., stack-based integer class as just a wrapper around the arithmetic algorithms?
Maybe, if one wants to implement all the free functions for their type. :-) I hadn't considered that anyone might want to.
Also, I don't see any allocator template parameters anywhere. I'm guessing any consideration of acceptance into boost is conditional on allocator support.
<sigh> I wish someone had mentioned that before. Not that it makes that much difference... while trying to add the data-caching stuff to the fixed_integer types last night, I came to the conclusion that I needed something like that anyway.
Very nice work on the documentation. I'll have to continue to troll through it at my usually leisurely pace.
Thanks! - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvdrO0ACgkQp9x9jeZ9/wQr3gCbB9Iw7+KViC6zEbj2MCP5mDOD enEAn1wXmnAahgJpAZeyZW4YqRbkIaQV =3d5q -----END PGP SIGNATURE-----

on 02.05.2010 at 20:48 Chad Nelson wrote :
I'm curious: Are you researching, or do you have plans to research, more efficient multiplication algorithms (Karatsuba's, FFT-based, etc.)? I believe these only become efficient at large integers, but I'm not sure how large...
Yes, I already have a description of the Karatsuba one to work from, for a later release. It's supposed to be more effective than the traditional version once you get past a certain size, but I don't know what that size is yet. Once that's added, I'll look into the others.
wikipedia says that kartsuba gains any advantage starting from ~10000 _decimal_ digits (that is roughly )
Okay, some questions regarding the arithmetic functions: It looks like you have named free functions for all the arithmetic operators which have identical functionality to the overloaded arithmetic operators. This was obviously deliberate. Can you comment on this decision, i.e., why have the named free functions at all?
Originally those were the functions that handled the internals. I had to move the internals down by another layer of abstraction in order to efficiently handle the fixed_integer types, and I just never thought to remove the free functions.
Do you have free functions that implement the low-level arithmetic operations for just pairs of pointers? [...]
Not pairs of pointers, but I do have lower-level functions (the ones in the detail namespace) that work on base_integer types.
? Okay this signature is probably not what you'd want, but
[...] more fundamentally my question is, have you separated the arithmetic/numeric algorithms from the memory management algorithms?
They're separated, in that the memory management is all done by the base_integer class, and the math is handled by the higher classes and free functions.
Can one build their own, e.g., stack-based integer class as just a wrapper around the arithmetic algorithms?
Maybe, if one wants to implement all the free functions for their type. :-) I hadn't considered that anyone might want to.
Also, I don't see any allocator template parameters anywhere. I'm guessing any consideration of acceptance into boost is conditional on allocator support.
<sigh> I wish someone had mentioned that before. Not that it makes that much difference... while trying to add the data-caching stuff to the fixed_integer types last night, I came to the conclusion that I needed something like that anyway.
Very nice work on the documentation. I'll have to continue to troll through it at my usually leisurely pace.
Thanks!
-- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 04:39 PM, DE wrote:
I'm curious: Are you researching, or do you have plans to research, more efficient multiplication algorithms (Karatsuba's, FFT-based, etc.)? I believe these only become efficient at large integers, but I'm not sure how large...
Yes, I already have a description of the Karatsuba one to work from, for a later release. It's supposed to be more effective than the traditional version once you get past a certain size, but I don't know what that size is yet. Once that's added, I'll look into the others.
wikipedia says that kartsuba gains any advantage starting from ~10000 _decimal_ digits (that is roughly )
Ah, thanks. I'll have to run my own tests to confirm it, once I've implemented Karatsuba, but it sounds like that wouldn't be used all that often, at least with the size of numbers that I'm used to dealing with. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvd6L8ACgkQp9x9jeZ9/wShBwCePVfHkE7tTbC4HgKhnA/ivJza /C0An1MuCzur+6+fMZQS124t/lRYp3ef =Ic3i -----END PGP SIGNATURE-----

on 02.05.2010 at 20:48 Chad Nelson wrote :
I'm curious: Are you researching, or do you have plans to research, more efficient multiplication algorithms (Karatsuba's, FFT-based, etc.)? I believe these only become efficient at large integers, but I'm not sure how large...
Yes, I already have a description of the Karatsuba one to work from, for a later release. It's supposed to be more effective than the traditional version once you get past a certain size, but I don't know what that size is yet. Once that's added, I'll look into the others.
wikipedia says that kartsuba gains any advantage starting from ~10000 _decimal_ digits (that is roughly 30000 bits) i don't know if that is practical to have an implementation onboard unless you want to multiply numbers of order of googolplex sorry for spurious reply -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/02/2010 04:46 PM, DE wrote:
wikipedia says that kartsuba gains any advantage starting from ~10000 _decimal_ digits (that is roughly 30000 bits) i don't know if that is practical to have an implementation onboard unless you want to multiply numbers of order of googolplex
Sheesh... that's even larger than I thought it would be. I rarely use anything more than 4000 bits for my work, at present. I have to wonder if Wikipedia is right on that, n1692 seems to suggest a much lower number (10^2 to 10^3 decimal digits, if I'm reading it right).
sorry for spurious reply
And I'm sorry that I didn't see this one before I replied to the earlier one. :-) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvd6bkACgkQp9x9jeZ9/wSTLwCgs8fh7jIBT5d/37uies8k07mu NREAnjjuJSMV3I57d9Z+USelClSZNnJh =xDnN -----END PGP SIGNATURE-----

Hi Chad ! On Friday 30 April 2010 07:35:13 you wrote:
I'm happy to announce that the third release of the Extended Integer library is ready, in both the sandbox and the Vault.
I've checked out the sandbox ...
Please take a look and let me know what you think of the changes. I'm very happy with them.
Well, I'm concentrating on Boost.Build issues. The rest looks nice. Please find some improvements to you current setup attached. xint.0.diff Uses <threading>multi to enable multi-thread support when compiling a multithreaded program. Uses <toolset>gcc to control gcc-specific flags. Adds library requierements to the test so both Boost.Xint and Boost.Test will be automagically rebuild if needed. This also pulls in "BOOST_TEST_DYN_LINK" as a usage-requirement of Boost.Test shared library. Uses "run" rule from Boost.Build test runner to run tests. Separates tests to singles files, need xint.1.diff to add "BOOST_TEST_MAIN" to each file. (I've replaced "DYN_LINK" with "MAIN" ) I've renamed test/Jamroot to "Jamfile" due to my local setup. It would be best to not use a "Jamroot" in libraries. If you need more help, please fell free to contact me. Impressive work, I think I can use it... Yours, Jürgen -- * Dipl.-Math. Jürgen Hunold ! Ingenieurgesellschaft für * voice: ++49 511 262926 57 ! Verkehrs- und Eisenbahnwesen mbH * fax : ++49 511 262926 99 ! Lister Straße 15 * juergen.hunold@ivembh.de ! www.ivembh.de * * Geschäftsführer: ! Sitz des Unternehmens: Hannover * Prof. Dr.-Ing. Thomas Siefer ! Amtsgericht Hannover, HRB 56965 * PD Dr.-Ing. Alfons Radtke !

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 08:37 AM, Juergen Hunold wrote:
Please take a look and let me know what you think of the changes. I'm very happy with them.
Well, I'm concentrating on Boost.Build issues. The rest looks nice. Please find some improvements to you current setup attached. [...]
Thanks, I was hoping to get some help with that... bjam isn't exactly an easy tool to learn. I'll take a look at your changes later today.
Impressive work, I think I can use it...
Thanks! - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkve97wACgkQp9x9jeZ9/wS9RwCeLAqVAs6fjt3LtvUD2hkPIIt/ xWkAoKi63csInalh9mVT044FQOFdjQ1C =ew+Z -----END PGP SIGNATURE-----

Hi Chad ! On Monday 03 May 2010 18:20:13 you wrote:
Thanks, I was hoping to get some help with that... bjam isn't exactly an easy tool to learn.
Yes, the learning curve is quite steep ;-)) Feel free to ask, I'm not a guru, but experienced users ;-)
I'll take a look at your changes later today.
Thanks. I found that the split up "test_add" case is running into a deadlock. Please find the helgrind dump attached. The code in "set_generator" ist trying to lock the mutext which is already locked in the constructor. By the way, why is "random_by_size" a class member ? A far as I can see it could very well be a free function. And I wonder about "return BOOST_XINT_MOVE(p);" instead of "return p;" and let the compiler optimise the return via NRVO...
Impressive work, I think I can use it...
Thanks!
You're welcome. I've been looking for a large integer as a building block for fixed decimal arithmetik for quite a while ;-)) Yours, Jürgen -- * Dipl.-Math. Jürgen Hunold ! Ingenieurgesellschaft für * voice: ++49 511 262926 57 ! Verkehrs- und Eisenbahnwesen mbH * fax : ++49 511 262926 99 ! Lister Straße 15 * juergen.hunold@ivembh.de ! www.ivembh.de * * Geschäftsführer: ! Sitz des Unternehmens: Hannover * Prof. Dr.-Ing. Thomas Siefer ! Amtsgericht Hannover, HRB 56965 * PD Dr.-Ing. Alfons Radtke !

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 12:35 PM, Juergen Hunold wrote:
Thanks, I was hoping to get some help with that... bjam isn't exactly an easy tool to learn.
Yes, the learning curve is quite steep ;-)) Feel free to ask, I'm not a guru, but experienced users ;-)
A couple years ago I decided to try switching to bjam for all my projects, and I have ever since. But getting things working with it has never been easy, and I'm never sure that I've gotten things correct.
I'll take a look at your changes later today.
Thanks. I found that the split up "test_add" case is running into a deadlock. Please find the helgrind dump attached. The code in "set_generator" ist trying to lock the mutext which is already locked in the constructor.
That makes sense, the test_add case wasn't designed to be split up. The changes that I'm planning will take care of that problem though.
By the way, why is "random_by_size" a class member ? A far as I can see it could very well be a free function.
:-? I'm not sure what you mean. It *is* a free function... or three, if you include nothrow_random_by_size and fixed_random_by_size. It would have been useful to make it a member function, since the three functions differ only in the types of their return values right now, but I didn't. Unless you're looking at a version of the library that I haven't written yet. ;-)
And I wonder about "return BOOST_XINT_MOVE(p);" instead of "return p;" and let the compiler optimise the return via NRVO...
Does NRVO work with emulated move semantics? I was under the impression that it couldn't, but I could well be wrong, Boost.Move is new to me. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfAHUACgkQp9x9jeZ9/wQCsQCfYkqzYyCHjfec3ATVpK+gYPZ/ Z2gAnj5Qnd9mnD97DSZRqBa5aYhcuix+ =TVrL -----END PGP SIGNATURE-----

On 5/3/2010 9:57 AM, Chad Nelson wrote:
On 05/03/2010 12:35 PM, Juergen Hunold wrote:
And I wonder about "return BOOST_XINT_MOVE(p);" instead of "return p;" and let the compiler optimise the return via NRVO...
Does NRVO work with emulated move semantics? I was under the impression that it couldn't, but I could well be wrong, Boost.Move is new to me.
RVO works independently of (emulated) move semantics. If you have the following code (similar example as before): T f() { return T(...); } void g(T) { ... } then in the expression "g(f())", the compiler is allowed to elide the copy from the return statement in f() all the way to the T parameter in g (and most compilers will perform this copy elision). In practice, the copy constructor of T is never called (except, of course, where it is used explicitly in the body of f and g)! Similarly, the statement "T x = f();" ostensibly requires 1 or more calls to T's copy constructor, but, again, in practice, most modern compilers elide these away. Actually, if f is defined as T f() { return move(T(...)); } then this could actually be *less* efficiently, since it will invoke an additional move construction over using the original definition of f! One of the main things (emulated) move semantics gives you is the ability to overload functions on lvalue or (emulated) rvalue reference, giving you the opportunity to capture temporaries and pilfer/reuse their resources. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 01:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
And I wonder about "return BOOST_XINT_MOVE(p);" instead of "return p;" and let the compiler optimise the return via NRVO...
Does NRVO work with emulated move semantics? I was under the impression that it couldn't, but I could well be wrong, Boost.Move is new to me.
RVO works independently of (emulated) move semantics. [...] One of the main things (emulated) move semantics gives you is the ability to overload functions on lvalue or (emulated) rvalue reference, giving you the opportunity to capture temporaries and pilfer/reuse their resources.
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfEdgACgkQp9x9jeZ9/wTyYwCgvZRT5YsK8VK+KRCVXUVItpGU gdwAnjLqM+6VHby5Cw9B6bdQ2BUJgmUN =wV3I -----END PGP SIGNATURE-----

On 5/3/2010 11:11 AM, Chad Nelson wrote:
On 05/03/2010 01:45 PM, Jeffrey Lee Hellrung, Jr. wrote:
And I wonder about "return BOOST_XINT_MOVE(p);" instead of "return p;" and let the compiler optimise the return via NRVO...
Does NRVO work with emulated move semantics? I was under the impression that it couldn't, but I could well be wrong, Boost.Move is new to me.
RVO works independently of (emulated) move semantics. [...] One of the main things (emulated) move semantics gives you is the ability to overload functions on lvalue or (emulated) rvalue reference, giving you the opportunity to capture temporaries and pilfer/reuse their resources.
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all?
Hmmm...good question. For something like "w = x * y + z", if you can't reuse any resources, I don't think move semantics will give you anything other than optimizing the final assignment...but then you could always accept your argument to operator= by value and swap it with *this (indeed, this is how a move assignment operator was emulated in the original Boost.Move code). COW should have similar performance. As pointed out by another (forgive me for not wanting to dig through this thread to find out exactly who), "w = x * y + z" would be maximally optimized by using expression templates. Perhaps someone could correct me if the above is misguided...? If you *can* reuse resources in some operators, it will help. But it seems plausible, as you said, that maybe only operator+ and operator- qualify, and these probably wouldn't be bottlenecks in typical usage. It's possible that your internal implementations could make use of moving resources around, but it could also be equally expressible via swapping (your intentions just may not be as obvious). - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 02:26 PM, Jeffrey Lee Hellrung, Jr. wrote:
RVO works independently of (emulated) move semantics. [...]
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all?
Hmmm...good question. For something like "w = x * y + z", if you can't reuse any resources, I don't think move semantics will give you anything other than optimizing the final assignment... [...]
Sorry, I meant why does adding Boost.Move make any difference to the timings I posted yesterday at all, if the compiler is already eliding the copy operations on return values even without it? If I understand what you're trying to explain (which is far from certain), there's no need to wrap the return values in a boost::move call, but in that case Boost.Move should be completely superfluous -- the code should run at the same speed with or without it. I just realized that, since I have the boost::move calls wrapped in a #define already, it would be easy to check on that, so I did. The timings all indicate that without the boost::move() call for the return values, XInt runs as if Boost.Move weren't even there. So the boost::move call *is* required to get the benefits of emulated move semantics, as I originally thought. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfRj0ACgkQp9x9jeZ9/wQwvwCgtCUiDrDRdHZvjg8EBqdzXDxY raEAoOY4N5VFF1qlHSNBFehbW8QpgpHD =z0hb -----END PGP SIGNATURE-----

On 5/3/2010 2:55 PM, Chad Nelson wrote:
On 05/03/2010 02:26 PM, Jeffrey Lee Hellrung, Jr. wrote:
RVO works independently of (emulated) move semantics. [...]
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all?
Hmmm...good question. For something like "w = x * y + z", if you can't reuse any resources, I don't think move semantics will give you anything other than optimizing the final assignment... [...]
Sorry, I meant why does adding Boost.Move make any difference to the timings I posted yesterday at all, if the compiler is already eliding the copy operations on return values even without it? If I understand what you're trying to explain (which is far from certain), there's no need to wrap the return values in a boost::move call, but in that case Boost.Move should be completely superfluous -- the code should run at the same speed with or without it.
I just realized that, since I have the boost::move calls wrapped in a #define already, it would be easy to check on that, so I did. The timings all indicate that without the boost::move() call for the return values, XInt runs as if Boost.Move weren't even there. So the boost::move call *is* required to get the benefits of emulated move semantics, as I originally thought.
Sorry, I *definitely* should've added that, as far as I know, RVO generally requires a single, simple return statement. If you have multiple returns, or a return expression more complicated than "return foo;" or "return T(bar,zap);", then I don't think RVO typically kicks in. Can you confirm or deny this to be the case? If it is, then the move(...) calls or COW will almost certainly be necessary to get optimal performance. Again, my apologies for maybe oversimplifying the situation and misleading you. See http://en.wikipedia.org/wiki/Return_value_optimization for more information on RVO. - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 06:37 PM, Jeffrey Lee Hellrung, Jr. wrote:
[...] I just realized that, since I have the boost::move calls wrapped in a #define already, it would be easy to check on that, so I did. The timings all indicate that without the boost::move() call for the return values, XInt runs as if Boost.Move weren't even there. So the boost::move call *is* required to get the benefits of emulated move semantics, as I originally thought.
Sorry, I *definitely* should've added that, as far as I know, RVO generally requires a single, simple return statement. If you have multiple returns, or a return expression more complicated than "return foo;" or "return T(bar,zap);", then I don't think RVO typically kicks in. Can you confirm or deny this to be the case? If it is, then the move(...) calls or COW will almost certainly be necessary to get optimal performance.
In the cases I'm looking at, there are usually only three lines in the function: a declaration of an integer to hold the return value, a call to a function in the detail namespace to do the operation (with the return value object as a parameter), and a return of the return value. - From what you're saying, RVO should be easy for the compiler to use, but the boost::move call on that return value is still required to get the benefits of move semantics. (That three-line function design is what is preventing the move semantics from working as well as they could, I'm pretty sure. I haven't had enough time to confirm that yet though.) - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfU7IACgkQp9x9jeZ9/wT9pwCfYczPIAy9k6CRzSnw2H3eZZCv CfQAoM0X8ozVCdeM+yISDb+AKo9sGb/Y =oLXq -----END PGP SIGNATURE-----

On 5/3/2010 3:52 PM, Chad Nelson wrote:
On 05/03/2010 06:37 PM, Jeffrey Lee Hellrung, Jr. wrote:
[...] I just realized that, since I have the boost::move calls wrapped in a #define already, it would be easy to check on that, so I did. The timings all indicate that without the boost::move() call for the return values, XInt runs as if Boost.Move weren't even there. So the boost::move call *is* required to get the benefits of emulated move semantics, as I originally thought.
Sorry, I *definitely* should've added that, as far as I know, RVO generally requires a single, simple return statement. If you have multiple returns, or a return expression more complicated than "return foo;" or "return T(bar,zap);", then I don't think RVO typically kicks in. Can you confirm or deny this to be the case? If it is, then the move(...) calls or COW will almost certainly be necessary to get optimal performance.
In the cases I'm looking at, there are usually only three lines in the function: a declaration of an integer to hold the return value, a call to a function in the detail namespace to do the operation (with the return value object as a parameter), and a return of the return value. - From what you're saying, RVO should be easy for the compiler to use, but the boost::move call on that return value is still required to get the benefits of move semantics.
(That three-line function design is what is preventing the move semantics from working as well as they could, I'm pretty sure. I haven't had enough time to confirm that yet though.)
Hmmm....can you give a stripped-down example of where you expect (or, perhaps, where I claim) RVO should kick in, but doesn't? I tried the following program to test RVO, and emulated the basic function structure you describe above. -------------------------------- #include <iostream> struct X { int x; X() : x(0) { std::cout << "X::X()" << std::endl; } X(const X& other) : x(other.x) { std::cout << "X::X(const X&)" << std::endl; } }; void f(X& x) { x.x = 1; } X g() { X x; f(x); return x; } int main() { X x = g(); return 0; } -------------------------------- With MSVC9, debug build gives output "X::X()"/"X::X(const X&)", while release build gives output "X::X()" (i.e., no call to X::X(const X&)). - Jeff

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/04/2010 02:03 AM, Jeffrey Lee Hellrung, Jr. wrote:
Sorry, I *definitely* should've added that, as far as I know, RVO generally requires a single, simple return statement. [...]
In the cases I'm looking at, there are usually only three lines in the function: a declaration of an integer to hold the return value, a call to a function in the detail namespace to do the operation (with the return value object as a parameter), and a return of the return value. - From what you're saying, RVO should be easy for the compiler to use, but the boost::move call on that return value is still required to get the benefits of move semantics.
(That three-line function design is what is preventing the move semantics from working as well as they could, I'm pretty sure. I haven't had enough time to confirm that yet though.)
Hmmm....can you give a stripped-down example of where you expect (or, perhaps, where I claim) RVO should kick in, but doesn't?
We may be talking about two different things. I was responding to Juergen Hunold's comment about whether the calls to boost::move (via the BOOST_XINT_MOVE macro) were necessary, and suggesting that I could increase efficiency by leaving the boost::move part out and letting the compiler optimize the return via NRVO. I tested it and proved that, at least for emulated move semantics, the boost::move call was necessary to get any benefit out of Boost.Move. I thought that the "three line function design" I mentioned might be at least partly responsible for why the copy-on-write design is faster than move semantics, but after looking at the way it's set up, I'm not so sure about that anymore. I didn't have enough time to actually test it today, but it's high on my to-do list for tomorrow.
I tried the following program to test RVO, and emulated the basic function structure you describe above. [...] With MSVC9, debug build gives output "X::X()"/"X::X(const X&)", while release build gives output "X::X()" (i.e., no call to X::X(const X&)).
Hm... I'm not sure what to make of that, because if it's true (and I'm not doubting it), Boost.Move shouldn't make any difference whatsoever -- the code should be just as fast or faster without it. But Boost.Move *does* provide a measurable speed increase over not using it (when copy-on-write isn't being used in either case). In any case, that's pretty strong evidence that that design isn't responsible for the difference. Assuming, of course, that GCC is doing the same thing, which I'll confirm as soon as I can tomorrow. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfw2kACgkQp9x9jeZ9/wRQigCfTx5XJZ4d0Kss/fOa9UnFOTon LeUAoMmAGHO05ND/6OulA/lQ7T2CFfzx =Y6pm -----END PGP SIGNATURE-----

Chad Nelson:
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all?
Consider something like X f(); g( X ); int main() { f( g() ); // #1 f( -g() ); // #2 } In #1, the compiler can eliminate all copies, if f is written in a RVO-friendly way. (It won't be able to in general if there's more than one return statement, or the return value is a ternary ?: expression.) But in #2, there's going to be one allocation for the result of the unary op-. Even if operator- takes its parameter by value and directly flips its sign and returns it, I don't think that the compiler is allowed to allocate the return value and the parameter at the same address.

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 04:47 PM, Peter Dimov wrote:
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all?
Consider something like [...]
Thanks, but I can't relate any of that to the reason for my question, which was whether the compiler would somehow magically use emulated move semantics if I just included Boost.Move in the code, without calling the boost::move function on the return values. I think I've proven that it wouldn't, and that the boost::move call is required to reap any benefit from emulated move semantics. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfTvUACgkQp9x9jeZ9/wQoHQCfbrKGlR9FmpWGqy6BgGAZ4bUU WnkAnj/5xtmx9JnfOpB3qri9XphBLY5V =g1q3 -----END PGP SIGNATURE-----

On Mon, May 3, 2010 at 9:47 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Chad Nelson:
If that's the case, and GCC is doing that as it should, why would adding move semantics to the library provide any speed increase at all?
Consider something like
X f(); g( X );
int main() { f( g() ); // #1 f( -g() ); // #2 }
In #1, the compiler can eliminate all copies, if f is written in a RVO-friendly way. (It won't be able to in general if there's more than one return statement, or the return value is a ternary ?: expression.)
But in #2, there's going to be one allocation for the result of the unary op-. Even if operator- takes its parameter by value and directly flips its sign and returns it, I don't think that the compiler is allowed to allocate the return value and the parameter at the same address.
No, but swap is your friend: X operator- (X x) { modify-in-place x; X ret; // this should be cheap ret.swap(x); return ret; // NRVO should kick in } HTH, -- gpd

on 04.05.2010 at 14:25 Giovanni Piero Deretta wrote :
Chad Nelson: [...] In #1, the compiler can eliminate all copies, if f is written in a RVO-friendly way. (It won't be able to in general if there's more than one return statement, or the return value is a ternary ?: expression.)
But in #2, there's going to be one allocation for the result of the unary op-. Even if operator- takes its parameter by value and directly flips its sign and returns it, I don't think that the compiler is allowed to allocate the return value and the parameter at the same address.
No, but swap is your friend:
X operator- (X x) { modify-in-place x;
X ret; // this should be cheap ret.swap(x); return ret; // NRVO should kick in }
i don't think it is a good idea to write such curious code in chase of a _possibility_ (there are no guarantees) of rvo -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Giovanni Piero Deretta wrote :
No, but swap is your friend:
X operator- (X x) { modify-in-place x;
X ret; // this should be cheap ret.swap(x); return ret; // NRVO should kick in }
i don't think it is a good idea to write such curious code in chase of a _possibility_ (there are no guarantees) of rvo
That's perfectly reasonable code. Consider <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 04.05.2010 at 15:30 Stewart, Robert wrote :
DE wrote:
Giovanni Piero Deretta wrote :
No, but swap is your friend:
X operator- (X x) { modify-in-place x;
X ret; // this should be cheap ret.swap(x); return ret; // NRVO should kick in }
i don't think it is a good idea to write such curious code in chase of a _possibility_ (there are no guarantees) of rvo
That's perfectly reasonable code. Consider <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>.
i've read the article (rather boring one) i don't understand how is that different to X operator- (const X &x) { X ret(x); //modify 'ret' return ret; } what about idiomatic return X().swap(x); //x is modified -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

DE wrote:
Stewart, Robert wrote :
DE wrote:
Giovanni Piero Deretta wrote :
No, but swap is your friend:
X operator- (X x) { modify-in-place x;
X ret; // this should be cheap ret.swap(x); return ret; // NRVO should kick in }
i don't think it is a good idea to write such curious code in chase of a _possibility_ (there are no guarantees) of rvo
That's perfectly reasonable code. Consider <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>.
i don't understand how is that different to
X operator- (const X &x) { X ret(x); //modify 'ret' return ret; }
As the article states, the compiler can elide the copy in various cases. With your version, the copy is unconditional.
what about idiomatic
return X().swap(x); //x is modified
That incurs the default constructor overhead, whatever that may be, before the swap. That also requires that the function argument be a reference to non-const X and the caller would be justifiably surprised at the effect. _____ Rob Stewart robert.stewart@sig.com Software Engineer, Core Software using std::disclaimer; Susquehanna International Group, LLP http://www.sig.com IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

on 04.05.2010 at 19:36 Stewart, Robert wrote :
DE wrote:
i don't understand how is that different to
X operator- (const X &x) { X ret(x); //modify 'ret' return ret; }
As the article states, the compiler can elide the copy in various cases. With your version, the copy is unconditional.
now i'm confused will the copy be elided in this case?
what about idiomatic
return X().swap(x); //x is modified
That incurs the default constructor overhead, whatever that may be, before the swap. i see
That also requires that the function argument be a reference to non-const X and the caller would be justifiably surprised at the effect. of course or 'x' being an argument passed by value
but what about copy elision? -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

On Tue, May 4, 2010 at 4:16 PM, DE <satan66613@yandex.ru> wrote:
on 04.05.2010 at 15:30 Stewart, Robert wrote :
DE wrote:
Giovanni Piero Deretta wrote :
No, but swap is your friend:
X operator- (X x) { modify-in-place x;
X ret; // this should be cheap ret.swap(x); return ret; // NRVO should kick in }
i don't think it is a good idea to write such curious code in chase of a _possibility_ (there are no guarantees) of rvo
That's perfectly reasonable code. Consider <http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/>.
i've read the article (rather boring one)
i don't understand how is that different to
X operator- (const X &x) { X ret(x); //modify 'ret' return ret; }
Then you haven't read the article carefully enough ;) The idea is that rvalues passed to operator- (like in Peter's example) won't be copied due to elision of temporaries. Only lvalue parameters will be copied (you can't avoid that of course), while in your example you have an unconditional copy to initialize ret.
what about idiomatic
return X().swap(x); //x is modified
my swap functions (and IIRC standard container swap functions) usually return void so it won't work in generic code, but if it works for your case, sure. Usually I refactor the pattern in a function like this: template<typename T> T move_swap(T& x) { // T is default constructible and swappable T ret; using std::swap; swap(x, ret); return ret; } So your operator- would look like this: X operator- (X x) { modify x; return move_swap(x); } -- gpd

on 04.05.2010 at 19:36 Giovanni Piero Deretta wrote :
Then you haven't read the article carefully enough ;)
The idea is that rvalues passed to operator- (like in Peter's example) won't be copied due to elision of temporaries. Only lvalue parameters will be copied (you can't avoid that of course), while in your example you have an unconditional copy to initialize ret.
oh! now i get it the argument _must_ be passed by value for copy elision to be possible is that right?
what about idiomatic
return X().swap(x); //x is modified
my swap functions (and IIRC standard container swap functions) usually return void so it won't work in generic code, but if it works for your case, sure. Usually I refactor the pattern in a function like this:
template<typename T> T move_swap(T& x) { // T is default constructible and swappable T ret; using std::swap; swap(x, ret); return ret; }
So your operator- would look like this:
X operator- (X x) { modify x; return move_swap(x); }
you are absolutly right about swap() but that move_swap seems a truly perversion to me now ... however now i can find some logic under it -- Pavel P.S. if you notice a grammar mistake or weird phrasing in my message please point it out

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 12:35 PM, Juergen Hunold wrote:
I'll take a look at your changes later today.
Thanks. I found that the split up "test_add" case is running into a deadlock. Please find the helgrind dump attached. The code in "set_generator" ist trying to lock the mutext which is already locked in the constructor.
I believe I've fixed that now, by eliminating the need for locking entirely. The changes are in the sandbox, please check them when you have a moment and let me know if you have any further problems with it. - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfslEACgkQp9x9jeZ9/wQGBQCg9OSLESWPnZtPtsscobvL3uMI v0MAoNqJgG5fmHE4ujXcIo/P746BOnhw =tVbg -----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/03/2010 08:37 AM, Juergen Hunold wrote:
Well, I'm concentrating on Boost.Build issues. The rest looks nice. Please find some improvements to you current setup attached. [...]
I'm confused... I thought you'd done something different. Why did you split up the test program into multiple programs? What benefit does that offer over a single executable? - -- Chad Nelson Oak Circle Software, Inc. * * * -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkvfW60ACgkQp9x9jeZ9/wRG3ACg6xMUu219ho05GvKbVw2MNRZ+ cq8AoMzIajGD4vqipPjzReQLZ7ad4YdC =qJGy -----END PGP SIGNATURE-----
participants (21)
-
Chad Nelson
-
Christopher Jefferson
-
Daniel F.
-
DE
-
Frank Mori Hess
-
Giovanni Piero Deretta
-
Jeffrey Hellrung
-
Jeffrey Lee Hellrung, Jr.
-
joel falcou
-
Juergen Hunold
-
Kim Barrett
-
Marius
-
Marius Stoica
-
Neal Becker
-
Peter Dimov
-
Scott McMurray
-
Steven Watanabe
-
Stewart, Robert
-
Vicente Botet Escriba
-
vicente.botet
-
Vladimir Prus