Tuesday, September 15, 2015

Digest for comp.lang.c++@googlegroups.com - 10 updates in 3 topics

maddoxr@acm.org: Sep 15 10:21AM -0700

On Monday, September 14, 2015 at 6:09:32 PM UTC-4, Ramine wrote:
 
> http://waitbutwhy.com/2015/01/artificial-intelligence-revolution-2.html
 
> Thank you,
> Amine Moulay Ramdane.
 
Wow! Far off topic, but so interesting there should be no complaint. :-)
 
Randy.
"Öö Tiib" <ootiib@hot.ee>: Sep 14 06:42PM -0700

On Monday, 14 September 2015 21:26:45 UTC+3, mark wrote:
 
> I'm stuck with using that C library. Converting the data structures to
> C++ ones is not an option.
 
> How unsafe is it?
 
When you know that exactly S1* is (implicit or static_) cast to void*
then it is guaranteed to be safe to cast it back.
 
Casting pointers to arrays of pointers you run into territory that
standard does not guarantee:
 
"A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and
alignment requirements. All pointers to structure types shall
have the same representation and alignment requirements as each
other."
 
So it does not say that void and struct pointer have same requirements.
When you don't know if void pointers and struct pointers have same
size and alignment requirements then you can at least static assert that.
 
static_assert( alignof(void*)==alignof(S1*)
&& sizeof(void*)==sizeof(S1*)
, "We need to cast between void** and S1** here!" );
 
I do not know any way to static assert any bitwise representation
however since 'reinterpret_cast' is not required to work compile time.
 
Bitwise representation is same on all implementations I know of
to make the casts cheap for C programs so it is perhaps risk worth
taking being stuck like you describe.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Sep 15 09:01AM

On Mon, 2015-09-14, Martin Shobe wrote:
 
>> Is it safe to cast Vector::data to S1** / S2**?
 
> Technically no. Even getting data to point to an array of S1* or S2* is
> already a problem.
 
Aren't we talking about two different things?
 
void** foo = something_with_S1();
S1* s1 = static_cast<S1*>(foo[0]); // ok, if you're sure there are
// S1 objects there
S2* s2 = static_cast<S2*>(foo[0]); // not ok
 
S1** bar = static_cast<S1**>(foo); // error
 
That last line was what the OP asked for. And it doesn't even compile
-- I have to replace it with a C-style cast (or maybe
reinterpret_cast would be enough?)
 
I think of it as if sizeof(void*) may be larger than sizeof(S1*).
 
> However, chances are if it works in that direction,
> it will work in reverse and I don't see any better options. (Assuming
> you can't fix the C library.)
 
If he really needs an array of S1*, he could also copy into one,
element by element.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
mark <mark@invalid.invalid>: Sep 15 01:36PM +0200

The void** casting is a bit close to UB, so I'll probably avoid that.
 
I've come up with a nice kludge to wrap the C vector with zero overhead
(GCC optimizes the C++ wrapper completely away). This should have
well-defined behavior with C++11.
 
 
#include <boost/iterator/transform_iterator.hpp>
#include <iostream>
#include <memory>
 
typedef struct {
void** data;
unsigned int length;
} Vector;
 
typedef struct {
int i;
} S1;
 
typedef struct {
const char* s;
} S2;
 
static const int elem_count = 5;
static const char* int_str[] = {"0", "1", "2", "3", "4"};
 
void initTestVecS1(Vector& vec) {
vec.data = static_cast<void**>(malloc(sizeof(void*) * elem_count));
vec.length = elem_count;
for(int i = 0; i < elem_count; i++) {
vec.data[i] = new S1{i};
}
}
 
void initTestVecS2(Vector& vec) {
vec.data = static_cast<void**>(malloc(sizeof(void*) * elem_count));
vec.length = elem_count;
for(int i = 0; i < elem_count; i++) {
vec.data[i] = new S2{int_str[i]};
}
}
 
template<typename node_type>
node_type& cast_node(void* ptr) {
return *static_cast<node_type*>(ptr);
}
 
template<typename node_type>
struct VectorWrapper {
Vector data;
auto begin() {
return boost::make_transform_iterator(
&data.data[0], cast_node<node_type>);
}
auto end() {
return boost::make_transform_iterator(
&data.data[data.length], cast_node<node_type>);
}
static VectorWrapper<node_type>& toWrapper(Vector& vec) {
return *reinterpret_cast<VectorWrapper<node_type>*>(&vec);
}
};
 
int main() {
Vector v1; initTestVecS1(v1);
auto vw1 = VectorWrapper<S1>::toWrapper(v1);
 
for(int i = 0; i < elem_count; i++)
std::cout << static_cast<S1*>(v1.data[i])->i << " ";
std::cout << std::endl;
 
for(const auto& elem : vw1) std::cout << elem.i << " ";
std::cout << std::endl;
 
Vector v2; initTestVecS2(v2);
auto vw2 = VectorWrapper<S2>::toWrapper(v2);
 
for(const auto& elem : vw2) std::cout << elem.s << " ";
std::cout << std::endl;
}
Martin Shobe <martin.shobe@yahoo.com>: Sep 15 08:10AM -0500

On 9/15/2015 4:01 AM, Jorgen Grahn wrote:
 
>> Technically no. Even getting data to point to an array of S1* or S2* is
>> already a problem.
 
> Aren't we talking about two different things?
 
To a certain degree. The comments above are directed more to the
situation itself, as opposed to what can be done to retrieve the asked
for information. To the best of my knowledge, neither C nor C++ make any
provisions for passing around arrays of S1 * (or S2 *) as arrays of void *.
 
> void** foo = something_with_S1();
> S1* s1 = static_cast<S1*>(foo[0]); // ok, if you're sure there are
> // S1 objects there
 
No, even this isn't certain to be ok. It's ok if the array is an array
void * that happen to point to S1 objects. But the original description
is that it's an array of S1 *. (In all fairness, it's about as likely to
work as the last line, but neither C nor C++ require it to.)
 
> S2* s2 = static_cast<S2*>(foo[0]); // not ok
 
> S1** bar = static_cast<S1**>(foo); // error
 
> That last line was what the OP asked for.
 
Yes, and that's what I was talking about (except, as you note later, it
would need a c-style or reinterpret_cast).
 
> -- I have to replace it with a C-style cast (or maybe
> reinterpret_cast would be enough?)
 
> I think of it as if sizeof(void*) may be larger than sizeof(S1*).
 
There are other potential issues as well.
 
>> you can't fix the C library.)
 
> If he really needs an array of S1*, he could also copy into one,
> element by element.
 
At this point, even that isn't certain to work.
 
Martin Shobe
mark <mark@invalid.invalid>: Sep 15 03:59PM +0200

On 2015-09-15 15:10, Martin Shobe wrote:
> void * that happen to point to S1 objects. But the original description
> is that it's an array of S1 *. (In all fairness, it's about as likely to
> work as the last line, but neither C nor C++ require it to.)
 
The original description is sloppy. It's not strictly an array of S1*,
but rather an array of void* which point to S1.
 
The array is allocated for the proper void** size and accessed in line
with those static_casts. So the void* <-> S1* conversion magic happens.
scott@slp53.sl.home (Scott Lurndal): Sep 15 02:48PM

>but rather an array of void* which point to S1.
 
>The array is allocated for the proper void** size and accessed in line
>with those static_casts. So the void* <-> S1* conversion magic happens.
 
In any case, on any architecture that matters for C++ programming,
an array of pointers is an array of pointers whether they're pointers
to void or pointers to an object. Leaving aside the standard and UB,
casting (using reinterpret_cast or c-style casting) "void **" to "S1 **"
will work correctly.
Martin Shobe <martin.shobe@yahoo.com>: Sep 15 10:39AM -0500

On 9/15/2015 8:59 AM, mark wrote:
>> work as the last line, but neither C nor C++ require it to.)
 
> The original description is sloppy. It's not strictly an array of S1*,
> but rather an array of void* which point to S1.
 
Then the cast above is ok, and what I would recommend. Even if Scott
Lurndal is correct in his response, it's better to not make that
assumption unless there's a significant gain. For most uses, it's too
easy to wrap in something that does the correct thing for there to be a
significant gain.
 
Martin Shobe
mark <mark@invalid.invalid>: Sep 15 06:44PM +0200

On 2015-09-15 17:39, Martin Shobe wrote:
 
> assumption unless there's a significant gain. For most uses, it's too
> easy to wrap in something that does the correct thing for there to be a
> significant gain.
 
I'm happy with the C++ wrapper I posted - no overhead (and no UB
according to my reading of the standard).
 
Having been burned by aggressive standard interpretations of UB that GCC
has done in the past (resulting in miscompiled code), I try to avoid
grey areas.
Nobody <nobody@nowhere.invalid>: Sep 15 08:05AM +0100

On Mon, 14 Sep 2015 21:20:52 +0200, Christian Gollwitzer wrote:
 
>> Another option is a recursive approach based upon the sum/difference
>> formulae and half-angle formulae.
 
> which is usually called the CORDIC algorithm.
 
They're different algorithms. CORDIC is based upon adding or subtracting
angles of the form arctan(1/(2^n)); the half-angle approach uses angles of
the form pi/(2^n).
 
CORDIC is more efficient on simple hardware, as it only requires shift,
add/subtract, and a lookup table.
 
Half-angle doesn't require the lookup table, but it does require square
roots. But std::sqrt() doesn't appear to be constexpr either, so you'd
need to implement that as well.
 
The main advantage of half-angle over CORDIC or a Taylor series is that it
doesn't require a set of constants whose number and accuracy needs to
change according to the desired accuracy of the result. Although that
probably doesn't matter here.
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: