Sunday, March 29, 2020

Digest for comp.lang.c++@googlegroups.com - 16 updates in 4 topics

Jorgen Grahn <grahn+nntp@snipabacken.se>: Mar 28 08:51PM

On Sat, 2020-03-28, red floyd wrote:
> integers. For example, for the range [1, N), where N can be arbitrarily
> large. The problem to me appears to be that library algorithms only
> work on iterators.
 
Seems to me the real problem is you don't have iterators over [1, N).
 
Isn't there such a thing in Boost or something? If not, I imagine it
would be easy to write something so that:
 
const Range<int> r{1, 4711};
std::for_each(r.begin(), r.end(), f);
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Mar 29 09:28PM +0100

On Sat, 28 Mar 2020 11:04:00 -0700
> [END CODE]
 
> I don't want to duplicate something already written, is there
> something similar in the Standard Library?
 
I don't think there is anything in the standard library but I am not
update with everything that C++17/20 has been up to.
 
However, rather than provide a lazy version of for_each, you would be
better off using an lazy iterator to which you can apply std::for_each,
std::transform and so on. Something like:
 
class IntIter {
public:
typedef int value_type;
typedef int reference; // read only
typedef void pointer; // read only
typedef int difference_type;
typedef std::random_access_iterator_tag iterator_category;
private:
int val;
public:
explicit IntIter(value_type val_ = 0) noexcept : val(val_) {}
IntIter(const IntIter&) noexcept = default;
IntIter& operator=(const IntIter&) noexcept = default;
IntIter& operator++() noexcept {++val; return *this;}
IntIter operator++(int) noexcept {IntIter tmp = *this; ++val; return tmp;}
IntIter& operator--() noexcept {--val; return *this;}
IntIter operator--(int) noexcept {IntIter tmp = *this; --val; return tmp;}
IntIter& operator+=(difference_type n) noexcept {val += n; return *this;}
IntIter& operator-=(difference_type n) noexcept {val -= n; return *this;}
reference operator[](difference_type n) const noexcept {return val + n;}
reference operator*() const noexcept {return val;}
};
 
Take your pick with standard comparison operators:
 
inline bool operator==(IntIter iter1, IntIter iter2) noexcept {
return *iter1 == *iter2;
}
inline bool operator!=(IntIter iter1, IntIter iter2) noexcept {
return !(iter1 == iter2);
}
inline bool operator<(IntIter iter1, IntIter iter2) noexcept {
return *iter1 < *iter2;
}
inline bool operator>(IntIter iter1, IntIter iter2) noexcept {
return iter2 < iter1;
}
inline bool operator<=(IntIter iter1, IntIter iter2) noexcept {
return !(iter1 > iter2);
}
inline bool operator>=(IntIter iter1, IntIter iter2) noexcept {
return !(iter1 < iter2);
}
inline IntIter::difference_type operator-(IntIter iter1, IntIter iter2) noexcept {
return *iter1 - *iter2;
}
inline IntIter operator+(IntIter iter, IntIter::difference_type n) noexcept {
return IntIter{*iter + n};
}
inline IntIter operator-(IntIter iter, IntIter::difference_type n) noexcept {
return IntIter{*iter - n};
}
inline IntIter operator+(IntIter::difference_type n, IntIter iter) noexcept {
return iter + n;
}
jacobnavia <jacob@jacob.remcomp.fr>: Mar 29 11:18PM +0200

Le 28/03/2020 à 19:04, red floyd a écrit :
 
> I don't want to duplicate something already written, is there
> something similar in the Standard Library?
 
> -- red floyd
 
In C you woduld write:
 
1 typedef long long IntType;
2
3 IntType doRange(IntType start,IntType end,
4 IntType increment, IntType(*func)(IntType))
5 {
6 IntType i;
7 for (i=start; i<end; i+= increment)
8 func(i);
9 return i;
10 }
 
I hope I understood correctly...
danielaparker@gmail.com: Mar 29 02:52PM -0700

On Sunday, March 29, 2020 at 5:18:29 PM UTC-4, jacobnavia wrote:
> 9 return i;
> 10 }
 
> I hope I understood correctly...
 
That's my understanding. Also, note that
 
for (i=start; i<end; i+= increment)
func(i);
 
is more robust than the iterator alternative, for example
 
integer_iterator<int> first(1,10); // starting from 1, increment
// in steps of 10
integer_iterator<int> last(100, 10);
 
std::for_each(first, last, func);
 
would result in an infinite loop.
 
Daniel
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 29 08:40AM -0700

size_t constexpr g_LEN = 16u;
 
array<uint8_t, g_LEN> data;
 
auto const my_range =
v
| boost::adaptors::sliced(1,15)
| boost::adaptors::strided(2);
 
boost::range::transform(my_range,
my_range.begin(),
std::bind2nd(std::bit_xor<uint8_t>(),0xFF)
);
 
It's annoying that there isn't a form of "boost::range::transform" that only takes two arguments.
 
Can anyone think of a cleaner way of doing this that will work with any kind of container of objects of type "uint8_t"? I use "bind2nd" with "bit_xor" and "0xFF" in this snippet because I can't find the unary "bit_not" class. Is there such a thing?
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 29 05:48PM +0200

On 29.03.2020 17:40, Frederick Gotham wrote:
> any kind of container of objects of type "uint8_t"? I use "bind2nd"
> with "bit_xor" and "0xFF" in this snippet because I can't find the
> unary "bit_not" class. Is there such a thing? >
 
Well, assuming that your code is always dealing with 8-bit bytes, try
 
for( int i = 0; i < g_LEN; ++i ) { if( i%2 ) { data[i] = ~data[i]; }
 
Oh look, it's a one-liner. ;-)
 
 
- Alf
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 29 11:54AM -0400

On 3/29/20 11:40 AM, Frederick Gotham wrote:
...
>I use "bind2nd" with "bit_xor" and "0xFF" in this snippet because I can't find the unary "bit_not" class. Is there such a thing?
 
The bit_not class is described in 23.14.9.4, immediately after
23.14.9.3, which describes the bit_xor class.
Bonita Montero <Bonita.Montero@gmail.com>: Mar 29 05:56PM +0200

>     for( int i = 0; i < g_LEN; ++i ) { if( i%2 ) { data[i] = ~data[i]; }
 
Assuming we have a 2s-complement this would be faster:
 
void invertSecond( uint8_t *p, size_t n )
{
for( size_t i = 0; i != n; ++i )
p[i] ^= -(int8_t)(i & 1);
}
Bonita Montero <Bonita.Montero@gmail.com>: Mar 29 06:00PM +0200

>>      for( int i = 0; i < g_LEN; ++i ) { if( i%2 ) { data[i] = ~data[i]; }
 
> Assuming we have a 2s-complement this would be faster:
 
Or maybe not because the branch-prediction is able
to predict the regular pattern of your branches.
Bonita Montero <Bonita.Montero@gmail.com>: Mar 29 06:26PM +0200

> Or maybe not because the branch-prediction is able
> to predict the regular pattern of your branches.
 
I tested it; my variant is faster although the loop is
very larger:
 
#include <iostream>
#include <chrono>
#include <cstdint>
#include <vector>
#include <algorithm>
 
using namespace std;
using namespace chrono;
 
void invertSecondA( uint8_t *p, size_t n )
{
for( size_t i = 0; i != n; ++i )
p[i] ^= -(int8_t)(i & 1);
}
 
void invertSecondB( uint8_t *p, size_t n )
{
for( size_t i = 0; i != n; ++i )
if( i % 2 )
p[i] = ~p[i];
}
 
int main()
{
size_t const SIZE = 1024, // fits in L1
ROUNDS = 1'000'000;
vector<uint8_t> v( SIZE, 0 );
time_point<high_resolution_clock> start = high_resolution_clock::now();
for( size_t round = ROUNDS; round; --round )
invertSecondA( &v[0], SIZE );
double sA = (double)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / 1.0E9;
start = high_resolution_clock::now();
for( size_t round = ROUNDS; round; --round )
invertSecondB( &v[0], SIZE );
double sB = (double)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / 1.0E9;
cout << sA << endl << sB << endl;
}
 
This are the MSVC 2019 times:
0.533812
1.1952
And this are the g++ 6.3.0 times:
0.190201
0.401627
Christian Gollwitzer <auriocus@gmx.de>: Mar 29 06:39PM +0200

Am 29.03.20 um 18:26 schrieb Bonita Montero:
>         if( i % 2 )
>             p[i] = ~p[i];
> }
 
How about:
for( size_t i = 0; i < n; i+=2 )
p[i] = ~p[i];
}
 
?
 
Christian
Bonita Montero <Bonita.Montero@gmail.com>: Mar 29 06:49PM +0200

>       for( size_t i = 0; i < n; i+=2 )
>               p[i] = ~p[i];
>       }
 
That's too simple. ;-)
Christian Gollwitzer <auriocus@gmx.de>: Mar 29 08:27PM +0200

Am 29.03.20 um 18:49 schrieb Bonita Montero:
>>                p[i] = ~p[i];
>>        }
 
> That's too simple. ;-)
 
Indeed, that version is faster than what Alf posted, but not nearly as
fast as yours. Here is the output (I'm on macOS)
 
Apfelkiste:Tests chris$ clang++ -O2 --std=c++17 invert.cpp -march=native
Apfelkiste:Tests chris$ ./a.out
0.193238
1.62945
1.03101
Apfelkiste:Tests chris$ clang++ -v
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
 
Looking at the assembly output, your version is vectorized by the
compiler - and that is the secret behind the 5x speed improvement
(compared to my version). Because the whole thing is memory bound, and
by vectorizing the number of memory accesses can be significantly reduced.
 
Christian
 
 
#include <iostream>
#include <chrono>
#include <cstdint>
#include <vector>
#include <algorithm>
 
using namespace std;
using namespace chrono;
 
void invertSecondA( uint8_t *p, size_t n )
{
for( size_t i = 0; i != n; ++i )
p[i] ^= -(int8_t)(i & 1);
}
 
void invertSecondB( uint8_t *p, size_t n )
{
for( size_t i = 0; i != n; ++i )
if( i % 2 )
p[i] = ~p[i];
}
 
void invertSecondC( uint8_t *p, size_t n )
{
for( size_t i = 0; i < n; i+=2 )
p[i] = ~p[i];
}
 
 
int main()
{
size_t const SIZE = 1024, // fits in L1
ROUNDS = 5'000'000;
vector<uint8_t> v( SIZE, 0 );
time_point<high_resolution_clock> start = high_resolution_clock::now();
for( size_t round = ROUNDS; round; --round )
invertSecondA( &v[0], SIZE );
double sA = (double)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / 1.0E9;
start = high_resolution_clock::now();
for( size_t round = ROUNDS; round; --round )
invertSecondB( &v[0], SIZE );
double sB = (double)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / 1.0E9;
start = high_resolution_clock::now();
for( size_t round = ROUNDS; round; --round )
invertSecondC( &v[0], SIZE );
double sC = (double)duration_cast<nanoseconds>(
high_resolution_clock::now() - start ).count() / 1.0E9;
cout << sA << endl << sB << endl << sC << endl;
}
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 28 06:25PM -0400

On 3/28/20 5:12 PM, Öö Tiib wrote:
>> regardless of which value is passed to the function.
 
> Is it removed that when conditional expression evaluates into throw
> expression then it is not constant expression?
In n3337.pdf dated 2012-01-16, section 5.19p2 includes "an invocation of
a constexpr function with arguments that, when substituted by function
invocation substitution (7.1.5), do not produce a constant expression;"
as one of the things that fails to qualify as a constant expression.
 
n3797.pdf, dated 2013-10-13, drops that item from the list.
 
So it would appear that the change you're complaining about took place
about 7-8 years ago.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Mar 28 04:11PM -0700


> n3797.pdf, dated 2013-10-13, drops that item from the list.
 
> So it would appear that the change you're complaining about took place
> about 7-8 years ago.
 
Drafts of the C++ standard are available in this git repo:
 
https://github.com/cplusplus/draft
 
The commit that removed that wording is:
 
commit 7cb8947bec0eaf7788e75e3b36e23f4714e157a8
Author: Richard Smith <richard@metafoo.co.uk>
Date: 2012-05-05 19:59:36 -0700
 
N3652 Relaxing constraints on constexpr functions

Conflicts resolved as indicated by N3652.
 
N3652 is here: https://isocpp.org/files/papers/N3652.html
 
Relaxing constraints on constexpr functions
 
constexpr member functions and implicit const
 
This paper describes the subset of N3597 selected for inclusion in
C++14, relaxing a number of restrictions on constexpr
functions. These changes all received overwhelmingly strong or
unopposed support under review of the Evolution Working Group. It
also incorporates Option 2 of N3598.
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
xyz91987@gmail.com: Mar 28 07:47PM

Protect yourself and your loved ones !
KILL the coronavirus right now !
And save LOTS OF CASH
New tested, scientificly proven and amazing antivirus against coronavirus using Chloroquine and Colchicine
at very low price (33% discount)
Satisfaction garanteed or your money back !
 
http://als0p.atwebpages.com/coronavirus/coronavirus-en.php
 
Protégez-vous et vos proches!
TUEZ le coronavirus dès maintenant!
Et économisez BEAUCOUP D'ARGENT
Nouvel antivirus testé, scientifiquement prouvé et étonnant contre le coronavirus utilisant la Chloroquine et la Colchicine
à très bas prix (33% de réduction)
Satisfaction garantie ou agrent remie !
 
http://als0p.atwebpages.com/coronavirus/coronavirus-fr.php
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: