lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Performance of bourn_cast


From: Greg Chicares
Subject: Re: [lmi] Performance of bourn_cast
Date: Sat, 18 Mar 2017 23:55:06 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.6.0

On 2017-03-18 16:39, Vadim Zeitlin wrote:
> On Sat, 18 Mar 2017 16:17:01 +0000 Greg Chicares <address@hidden> wrote:
> 
> GC> Here are optimized and unoptimized speed measurements for the new cast
> GC> added in commit 5e36b0a6bc9fed0788b6f74a9896387c8a729cb4:
> 
>  It's going to get me some time to get used to the name of the new cast as
> it's not a word I use daily (and it doesn't help that it's much more common
> in French, but spelt differently there). It's probably not a very useful
> question, but why couldn't it be called lossless_cast<> or something like
> that instead (unfortunately my preferred name, "exact_cast" is already
> taken by something else)?

The obvious names are likely to have been used already by someone else
(the other day I found a 'value_cast' somewhere, which certainly doesn't
do exactly the same thing as lmi's). And in the case of 'exact_cast',
lmi already uses that name for a cast that I would say is more "exact"
than this one (it casts a "held" object to the exact type of its original
antecedent).

Here, I started out thinking of a name suggesting a boundary or barrier:
fenced_cast, for example. But most of the words like "fenced" that occurred
to me suggested an operation that forces the result to remain within limits;
whereas in this case, values are free to jump the fence--directly into an
exception handler. Anyway, I reached for a thesaurus, came across the word
"bourn", and thought, of course, of

  ... Who would fardels bear,
  To grunt and sweat under a weary life,
  But that the dread of something after death,
  The undiscovered country from whose bourn
  No traveler returns, puzzles the will
  And makes us rather bear those ills we have
  Than fly to others that we know not of?

That tickled my fancy: no value "returns" across this fence, because an
exception is thrown. And I personally prefer uncommon but pungent words
because they're easy to grep for: e.g.,
  grep fardel *make*
is more fruitfully selective than searching for a word like "install".

>  BTW, have you tried making the function constexpr? Regardless of the
> runtime performance, this would seem to be the right thing to do (although,

I'm curious--why is it the right thing? I probably don't understand this
well enough yet, but I'm thinking that could be helpful if, e.g., we have
an actual constant of one integer type and want to cast it to another type;
but I can't think of a practical use case. OTOH, if we have
  std::vector<whatever> vec(whatever);
  for(int j = 0; j < bourn_cast<int>(vec.size()); ++j)
then I hope the compiler would already hoist that '.size()' out of the loop;
yet maybe it would help to have a constexpr there--is that what you have in
mind? Or are you just saying that a function generally _should_ be constexpr
if it _can_ be constexpr?

I was also thinking of a case like
  for(int j = 0; bourn_cast<size_t>(j) < bourn_cast<int>(vec.size()); ++j)
where we'd be asking the compiler to...create and store a constant for
every value in [0, vec.size()] ? Is that what constexpr would mean there?
Is there any danger that the compiler would really do that, perhaps causing
enough bloat to empty the CPU cache and make the program slower? Sorry to
bother you with elementary questions, but I've deliberately been trying to
learn other things first because I understand constexpr functions change
from C++11 to C++14 to C++17 and I don't want to have to unlearn anything.

> admittedly, it risks being a little painful in C++11...).

Apparently g++-4.9.1 wants the body to be a single return statement.
If I just insert 'constexpr', it says:

error: body of constexpr function 'constexpr To bourn_cast(From) \
  [with To = long unsigned int; From = long int]' \
not a return-statement

That can be worked around as follows, but is it worth it?

---------8<--------8<--------8<--------8<--------8<--------8<--------8<-------
diff --git a/bourn_cast.hpp b/bourn_cast.hpp
index ab89b1e..451f8a8 100644
--- a/bourn_cast.hpp
+++ b/bourn_cast.hpp
@@ -70,7 +70,7 @@
 /// which may be an independent redesign.
 
 template<typename To, typename From>
-inline To bourn_cast(From from)
+inline constexpr To bourn_cast(From from)
 {
 #   if defined __GNUC__
 #       pragma GCC diagnostic push
@@ -81,13 +81,14 @@ inline To bourn_cast(From from)
     static_assert(  to_traits::is_specialized, "");
     static_assert(from_traits::is_specialized, "");
 
-    if(! to_traits::is_signed && from < 0)
-        throw std::runtime_error("Cast would convert negative to unsigned.");
-    if(from_traits::is_signed && from < to_traits::lowest())
-        throw std::runtime_error("Cast would transgress lower limit.");
-    if(to_traits::max() < from)
-        throw std::runtime_error("Cast would transgress upper limit.");
-    return static_cast<To>(from);
+    return
+       (! to_traits::is_signed && from < 0)
+        ? throw std::runtime_error("Cast would convert negative to unsigned.")
+      :(from_traits::is_signed && from < to_traits::lowest())
+        ? throw std::runtime_error("Cast would transgress lower limit.")
+      :(to_traits::max() < from)
+        ? throw std::runtime_error("Cast would transgress upper limit.")
+      :static_cast<To>(from);
 #   if defined __GNUC__
 #       pragma GCC diagnostic pop
 #   endif // defined __GNUC__
--------->8-------->8-------->8-------->8-------->8-------->8-------->8-------




reply via email to

[Prev in Thread] Current Thread [Next in Thread]