2d thrust::device_vector to kernel - c++

I have a data type defined as typedef InitialState float[12]. I have a vector containing several initial states defined by std::vector<InitialState> h_initials.
I made it a thrust device vector : thrust::device_vector<InitialState> d_initials = h_initials;
I would like to use this data is a user-defined kernel. However, I'm having problems casting it to a raw pointer. I've tried
float *p_initials = thrust::raw_pointer_cast(&d_initials[0]);
but thrust complains function returning array is not allowed.
Is there a way I can cast the device vector to a pointer that the kernel can use?

InitialState (float[12]) != float
InitialState *p_initials = thrust::raw_pointer_cast(d_initials.data());
float* p_floats = (float*)p_initials;
However, this is generally wrong to start with, because of the weird behavior below
typedef int int4[4];
void test(int4 a)
{
std::cout << sizeof(a) << std::endl;
}
int main(int argc, char** argv)
{
int4 f;
std::cout << sizeof(f) << std::endl;//returns 16 (4*sizeof(int))
test(f);//returns 8 (size of pointer, passes by reference)
}
Whats better is this:
struct InitialState{float value[12];}
std::vector<InitialState> h_initials;
thrust::device_vector<InitialState> d_initials = h_initials;
InitialState *p_initials = thrust::raw_pointer_cast(d_initials.data());
float* p_floats = (float*)p_initials;
And in cuda, you can use either InitialState* or float* as the argument (though SOA works better than AOS)

Related

Casting pointers to arrays in C++

Is it possible to cast pointers to arrays in C++?
Is casting pointers to arrays in C++, problem free? and / or, is it considered to be a good practice?
If it is possible, then what is the method of casting pointers to arrays in C++? and if there are problems with doing so, then how to avoid them?
Basically I am trying to cast a part of a const char[x] to const char[y], where y <= x and the Original const char[x] can not be accessed (in order to change it's forms to std::array or anything else) and (it's content) should not be copied to another array or pointer.
But to simplify the problem, lets consider the simple case of casting a pointerconst char *pointer; to an arrayconst char array[n];. I (guess) this can be accomplished by casting the address of the pointer to address of the array by (possibly) one of the following loosely described methods:
void *voidPointer = &pointer;
static_cast<const char (*)[n]>(voidPointer);
(const char (*)[n]) &pointer;
reinterpret_cast<const char (*)[n]>(&pointer);
And then reading the content of that address.
In order to test these cases of casting a pointer to an array , I ran the following code:
const char string[] = "123";
const char *pointer = string;
const char **pointerAddress = &pointer;
typedef const char array_type[sizeof(string) / sizeof(char)];
typedef array_type *arrayPointer_type;
void *voidPointer = pointerAddress;
arrayPointer_type arrayPointer[3];
arrayPointer[0] = static_cast<arrayPointer_type>(voidPointer);
arrayPointer[1] = (arrayPointer_type) pointerAddress;
arrayPointer[2] = reinterpret_cast<arrayPointer_type>(pointerAddress);
for(const arrayPointer_type& element : arrayPointer)
{
const char *array = *element;
bool sameValue = true;
bool sameAddress = true;
for(size_t idx = (sizeof(string) / sizeof(char)) - 1; idx--;) {
std::cout << "idx[" << idx << "]" << "pointer[" << pointer[idx]<< "]" << "array[" << array[idx]<< "], ";
if(pointer[idx] != array[idx]) {
sameValue = false;
}
if(&pointer[idx] != &array[idx]) {
sameAddress = false;
}
}
std::cout << std::endl << "sameValue[" << sameValue << "]" << "sameAddress[" << sameAddress << "]" <<std::endl <<std::endl;
}
And I got the following result:
idx[2]pointer[3]array[V], idx[1]pointer[2]array[], idx[0]pointer[1]array[�],
sameValue[0]sameAddress[0]
idx[2]pointer[3]array[V], idx[1]pointer[2]array[], idx[0]pointer[1]array[�],
sameValue[0]sameAddress[0]
idx[2]pointer[3]array[V], idx[1]pointer[2]array[], idx[0]pointer[1]array[�],
sameValue[0]sameAddress[0]
Which shows that non of the casts where correct in term of keeping(not changing) the content of string!
I studied Casting pointer to Array (int* to int[2]) and Passing a char pointer to a function accepting a reference to a char array , but I was not able to find the correct way!
So is it OK to cast pointers to arrays in C++? if so What is the correct way to cast pointers to arrays without changing their contents, in C++?
Update:
The library that I am working on is going to be used only on a very low resourced embedded platform and is going to be compiled only with GCC.
The reason for casting a portion of the const char [x] to const char [y] and then passing it to another functions or methods or ... is simply conformance with my other template functions or methods or ..., which can use the extra information in order to boost the speed of a process which it's current (non-optimized) version has already failed due to lack of speed. Please also note that the types of the strings that I want to deploy are not necessarily Null-terminated.
The following method is one example of such methods:
template<size_t STRING_SIZE>
requires conceptLowSize<STRING_SIZE>
self &operator<<(const char (&string)[STRING_SIZE])
{
.
.
.
return *this;
}
I am aware of the fact that deploying template functions/methods in this way might has the overhead of program size, but in this specific case, higher speed and lower memory consumption is more preferable than lower binary size of the compiled program.
Also I tried many other speed optimization solutions including compiling with -o3 option and the speed did not observably improve.
Your variable pointer contains the address of the first character in string; while, pointerAddress is a pointer to a variable containing the address of the first character in string. Basically pointerAddress has nothing to do with string so
void *voidPointer = pointerAddress;
arrayPointer_type arrayPointer[3];
arrayPointer[0] = static_cast<arrayPointer_type>(voidPointer);
arrayPointer[1] = (arrayPointer_type) pointerAddress;
arrayPointer[2] = reinterpret_cast<arrayPointer_type>(pointerAddress);
is all wrong in that it is all casting pointerAddress which contains the address of some other variable. The address of string is the address of its first character i.e. try this
void* voidPointer = const_cast<char*>(pointer);
arrayPointer_type arrayPointer[3];
arrayPointer[0] = static_cast<arrayPointer_type>(voidPointer);
arrayPointer[1] = (arrayPointer_type)pointer;
arrayPointer[2] = reinterpret_cast<arrayPointer_type>(pointer);

quickly cast a vector of unsigned char into a vector of POD struct and vice versa

I want to read/write binary data, essentially a vector of plain old data struct.
I managed to do so with arrays of char, but now I need to convert those arrays back and forth to an vector of struct.
I already managed to do this by reading/writing directly into files:
int main() {
struct thing { float f; char c; };
std::vector<thing> write_this = { {2,'c'},{5,'f'},{543,'e'} };
std::ofstream outfile{ "test.bin", std::ios::binary };
outfile.write(reinterpret_cast<const char *>(write_this.data()),
write_this.size() * sizeof(decltype(write_this)::value_type));
outfile.close();
std::vector<thing> result(3);
std::ifstream infile{ "test.bin", std::ios::binary };
infile.read(reinterpret_cast<char *>(result.data()),
result.size() * sizeof(thing));
for (auto& i : result)
std::cout << i.f << " " << i.c << ' ';
std::cout << '\n';
system("PAUSE");
return 0;
}
Since I want to store several different segments of data into a file, I'm using vectors of unsigned char as an intermediary. I now need to cast an array of char or vector of char to a vector of struct, and vice versa.
What's the simplest/cleanest/fastest way to do so?
Foreword: Note that the written data is not portable to other systems, and for some PODs (ones that contain bit fields) not even to other processes on same system compiled by a different compiler - unless those systems are somehow guaranteed to have identical binary representation.
Also, memory references in the written data will be meaningless to other processes, even to separate executions of the same program.
quickly cast a vector of unsigned char into a vector of POD struct and vice versa
You could do this:
static_assert(std::is_trivial_v<thing>);
constexpr int s = sizeof(thing);
int n = 3;
std::vector<unsigned char> result_raw(n * s);
unsigned char* data = result_raw.data();
infile.read(reinterpret_cast<char*>(data), n * s);
// ->
for(int i = 0; i < n; i++) {
unsigned char temp[s];
unsigned char* addr = data + i * s;
std::memcpy(temp, addr, s);
new (addr) thing;
std::memcpy(addr, temp, s);
}
thing* result = std::launder(reinterpret_cast<thing*>(data));
// <-
Now, you have a pointer to the first thing in the vector. Beautiful part about this is that the part between the arrow comments that creates the objects and makes the program well-defined compiles to zero instructions (as long as you enable optimisation).
You don't get a std::vector<thing> though. To get that, you must copy all of the from one vector another. Or you could read directly onto the vector of things like in your example. But you didn't want to do the latter, and former is slower than not copying.
In future, if p0593rX proposal is adopted, this block of code that does nothing could be greatly simplified.

function that returns an array of objects

I have got a structure
class pyatno {
int pyatnoNumber;
int locX, locY;
bool possible;
char *number;
char pyatnoView[4][4];
}
the idea is to make a function, that would return an array of pyatno.pyatnoView objects, but there is a mess. I don't understand how exactly I can get access to this "property". I am not strong in c++, so if it isn't real, or i am talking something wrong, explain please, cause I am really stacked in this question.
As you mentioned that you are not very strong with c++, and your question is rather unclear, here are several suggestions.
To get access to a class's attributes, c++ has the notion of visibility; The default visibility is private, that is, attributes and functions will not be visible outside of the class:
class Foo {
int some_value;
};
There are several ways you can retrieve data from an object, however to put it simply, you should either make the attribute public:
class Foo {
public:
int some_value;
};
or expose it via accessors/mutators:
class Foo {
int some_value;
public:
int get_some_value() { return some_value; }
void set_some_value(int v) { some_value = v; }
};
Another thing to note is that you can not return arrays! In c++, when an array passes a function boundary (that is to say, passed as a parameter to, or returned from), and in a lot of other cases, an array will 'decay' in to a pointer. For example, the following is how I would pass an array of characters (otherwise known as a c-string) to a function:
#include <iostream>
using namespace std;
void print_cstr(const char *cstr) {
cout << cstr << endl;
}
int main() {
const char my_cstr[20] = "foo bar baz qux";
print_cstr(my_cstr);
return 0;
}
So what happens for N-dimensional arrays? Well, if char[1] decays to char*, then char[1][1] will decay to char**, and so on. You might have noticed this with the older main signature in C programs, which is used to pass an array of strings representing arguments passed to the program:
int main(int argc, char **argv) { ... }
It is very important that you realise that this really is no longer an array. C style strings are a bit special, in that they are conventionally terminated with a null byte \0, which means that you can usually tell where the end of the string is, or how long it is. However, you no longer have any information on how long the array is! For example, this is completely legal:
#include <iostream>
using namespace std;
void bad_fn(const int *nums) {
for (unsigned i = 0; i < 20; ++i) {
cout << "num " << i << " = " << nums[i] << endl;
}
}
int main() {
const int my_nums[5] = { 1, 2, 3, 4, 5, };
bad_fn(my_nums);
return 0;
}
Your function will end up reading memory beyond the bounds of the array, as it has no way of knowing where the array begins or ends (after all, array indexes are just pointer arithmetic). If you do not want to have to worry about keeping track of, and passing around the length of your array (and I would suggest that you do not!), please look at using one of the C++ standard library's containers. std::vector and std::array are two examples that would fit in the use case you have provided, and you can find decent documentation for them here.

Setting class level 2D Array variable to passed in value - C++

I'm attempting to make a maze-solving program, and while the algorithm is sound (at least in my head), I've been running into a roadblock with 2D arrays. I'm coming from C# and Java, so the syntax is giving me grief.
Here's an SSCCE:
//Main.cpp
#include "MazeSolver.h"
int main()
{
MazeSolver mazeSolver;
char maze[51][51] = { }; // Not bothering to show code for populating the array
mazeSolver.setMaze(maze);
}
//MazeSolver.cpp
#include "MazeSolver.h"
MazeSolver::MazeSolver() { }
void MazeSolver::setMaze(char maze[51][51])
{
this->maze = maze;
}
//MazeSolver.h
#ifndef _MAZESOLVER_H
#define _MAZESOLVER_H
class MazeSolver
{
private:
char **maze; // This is likely the problem, I'm at wits end in regards to
// what notation is needed here. I do not want to hard-copy
// the entire array, I just need to access it (via pointer)
// I've also tried just using char maze[51][51] here, char *maze, etc...
public:
MazeSolver();
void setMaze(char maze[51][51]);
}
You cant assign (Or convert) 2d arrays (array[ROWS][COLUMNS]) to pointers to pointers (aka **) because the memory layout of a 2d array is (could be) very different to the memory layout the pointer of pointers could point to.
Check this thread for more info about this topic.
If suggest you to use the de facto C++ standard container, std::vector, instead of a plain array:
class MazeSolver
{
std::vector<std::vector<char>> maze;
void setMaze( const std::vector<std::vector<char>>& new_maze )
{
maze = new_maze;
}
};
Note that a vector has size 0 by default (At the point of its initialization), so you should fill it with elements:
for( std::size_t i = 0 i < ROWS ; ++i )
{
maze.push_back( std::vector<char>() );
for( std::size_t j = 0 ; j < COLUMNS ; ++j )
maze[i].push_back( ' ' );
}
However, C++11 (The current iteration of the language) has a std::array container which is like a C array but with the interface of other Standard Library Containers:
std::array<char,ROWS*COLUMNS> maze;
<rant>
This is one of the weird quirks of C++.
C++ 2D arrays are NOT jagged arrays. When you declare char maze[51][51], it actually allocates 1 contiguous array 51*51 members long. sizeof(maze) == 51*51. When you dereference a value, maze[a][b], what it actually does is *(maze+51*a+b). All this is under the hood.
A Jagged Array is an array of arrays, a char**. In this case, you have an array of 51 pointers size == (51*sizeof(void*)). In each position, the pointer points to a completely different memory location, allocated to 51 members long.
This is ANNOYING because you can't just convert the two, even by casting. You have to deal with weird syntax, such as char (*maze)[51] to get a pointer to the 2D array.
Whats even more annoying is the following happens:
int foo(int maze[51][51])
{
return sizeof(maze);
}
int maze[51][51];
int main(int argc, char** argv)
{
std::cout << sizeof(maze) << std::endl;//return 51*51*sizeof(int);
std::cout << foo(maze) << std::endl;//return 8, sizeof(void*);
}
So it implicitly passes by reference, not by value, which is opposite all the rest of C++.
</rant>
tl;dr;
The correct syntax for a pointer to a 2D array is char (*maze)[51];. Your syntax is for a jagged array (arrays of arrays) which is NOT the same thing in C++.

How to cast void* back to std::vector<float>

I can construct data on Line 19 from vvp.at(0) if I know the size of vf.
#include <iostream>
#include <vector>
typedef void* VoidPointer;
typedef std::vector< float > VF;
typedef std::vector< VoidPointer > VVP;
int main(int argc, char** argv)
{
VF vf;
vf.push_back(13.0f);
vf.push_back(14.0f);
vf.push_back(15.0f);
vf.push_back(16.0f);
VVP vvp;
vvp.push_back( (VoidPointer)const_cast<float *>( &(vf.front()) ) );
VF data ( static_cast< float* >( vvp.at(0) ),
static_cast< float* >( vvp.at(0) ) + vf.size() );
std::cout << "data.size() is " << data.size() << std::endl;
for(VF::const_iterator i = data.begin(); i != data.end(); ++i)
{
std::cout << "data contains " << *i << std::endl;
}
return 0;
}
Leaving aside whether this is sensible (the example is contrived) I'd like to know how to cast vvp.at(0) to a std::vector<float> if I didn't know the size of vf. I'm thinking along the lines of something like:
std::vector<float> data( *static_cast< std::vector<float>* >( vvp.at(0) ) );
But that causes the program to termintate with std::bad_alloc, I don't mind copying if need be.
That is not a cast from vvp.at(0) to a vector, it's a copy of an array of floats into a new vector. And you can't copy it without knowing the length. You only saved a pointer to the first element, so the information was lost.
You could make std::vector<std::pair<VoidPointer, size_t> > VVP and save both &vf.front() and vf.size() (or start and end pointers, if you prefer).
You could make std::vector<VF *> and store pointers to vectors (i.e. vvp.push_back(&vf)) and now there's no casting at all.
Edit: In case you didn't realize: The pointer &vf is unrelated to &vf.front(). vf is a structure which contains the pointer &vf.front() (or a way to get it). There's no information in just the address &vf.front() to let you find &vf.
The only thing I can think of is extremely non-portable (and equally crazy). Each vector allocates a contiguous array of memory. Any allocation function has to keep track of how many bytes have been allocated, so that it can de-allocate them given only the beginning of the allocation's address.
AFAIK, the C++ standard does not specify how this book keeping is done and therefore, this up to each compiler. One method is to write a count before the actual allocation address - I believe this is what the Visual C++ compiler does. (Eg. if allocating at 0x104, a 32-bit count could be stored at 0x100). Again, you will have to know how your specific compiler does this book keeping.
Anyway, the point is, once you do, a little pointer arithmetic and de-referencing could theoretically look up the allocated size (I'm of course assuming you're still using a vector with a default allocator here), and figure out how many floats were actually allocated using only a void pointer.
Here's an example that works in Visual Studio in 32-bit debug mode:
#include <iostream>
#include <vector>
size_t bytes_allocated( void* p )
{
#ifndef _DEBUG
#error Doesn't work
#endif // _DEBUG
size_t const offset = 12;
size_t const counter_size = 4;
size_t const total_offset = offset + counter_size;
void* counter_address = ((char*)p)-total_offset;
size_t* count = reinterpret_cast<size_t*>(counter_address);
return *count;
}
int main(int argc, char* argv[])
{
typedef float test_type;
std::vector<test_type> v;
v.push_back(23);
v.push_back(23);
v.push_back(23);
size_t count = bytes_allocated(&v[0]);
std::cout<<count<<" bytes allocated\n";
std::cout<<count/sizeof(test_type)<<" items allocated\n";
return 0;
}
The output is:
12 bytes allocated
3 items allocated