std::vector making struct sort slow? c++ - c++

I have a list of structs that I am sorting by one of the members. I am using std::sort with my own comparison function, that part is fine. However, I notice a (very) large performance gap when I change the struct from:
struct square
{
float x;
float y;
float z;
float scale;
float angle;
GLuint texture;
};
to
struct square
{
float x;
float y;
float z;
float scale;
float angle;
GLuint texture;
std::vector <float> color;
};
I have since used an entirely different method, and I realize that using a vector like this is a bad idea (I know the size of array - rgb) but I was wondering why I got the performance hit. I was comparing the z values to sort.
Here is my sorting function and struct list:
std::vector <square> square_list;
//Then add a bunch of squares
bool sort (square a,square b)
{
return a.z < b.z;
}
//Here is the sort that is slow
std::sort (square_list.begin(),square_list.end(),sort);
I wonder if it has anything to do with re-ordering the list of structs as their size is significantly bigger in the second case?
Thanks for any responses.

bool sort (square a,square b)
This copies the structs each time, including the vectors. Vectors are slower to copy than normal arrays. You should use this instead.
bool sort (const square& a, const square& b)
If you are using C++11, you can replace the vector with std::array as the size is constant.

In addition to take parameters as const ref you could use a functor for comparison. That is often faster because functors are more easy to inline.
std::vector <square> square_list;
//Then add a bunch of squares
struct sort
{
bool operator() (const square& a, const square& b) const {
return a.z < b.z;
}
}
std::sort (square_list.begin(),square_list.end(),sort);

sort copy your values every time and std::vector preallocate a bunch of memory. The amount of copy time is bigger

Did you try storing pointers instead of the whole struct in your vector?
std::vector <square*> square_list;
//Then add a bunch of squares
bool sort (square* a,square* b)
{
return a->z < b->z;
}
//Here is the sort that is slow
std::sort (square_list.begin(),square_list.end(),sort);

Related

Pass either a double or a vector<double>& to a function

I have a function which calculates the first derivative dy/dx for discrete values y(x) stroed as std::vector:
vector<double> CalcDerivative(vector<double>&y, vector<double>&x) {...}
Often the spacing dx is constant so it would be more efficient to pass a double to this function instead of vector<double> as argument x.
I tried to accomplish this with std::variant. The drawback with std::variant is however, that it cannot handle references so the vector x has to be copied while being passed as a variant to the function.
For now I solved the problem by defining two functions with overloaded arguments. But I wonder whether there is a more elegant solution which won't duplicate the code for the two cases (x as double or as vector<double>).
One possible solution might be to define the "worker" function such that it is independent of the "number of passed doubles". For this purpose, std::span is suitable. The exemplary solution might look like:
std::vector<double> CalcDWorker(
std::span<const double> y, std::span<const double> x)
{
... // x.size() == 1 indicates uniform spacing
}
std::vector<double> CalcDerivative(
const std::vector<double>& y, const std::vector<double>& x)
{
return CaclDWorker({y.begin(), y.end()}, {x.begin(), x.end()});
}
std::vector<double> CalcDerivative(
const std::vector<double>& y, double x)
{
return CaclDWorker({y.begin(), y.end()}, {&x, 1});
}
It requires C++20, but there are third-party span implementations available also for earlier C++ versions (such as the one provided by Boost).
Live demo: https://godbolt.org/z/n6adEKWes

sort vector of Coordinates(x,y,z) by vector of z value

I have a vector of 3D coordinates:
vector<float64>contourdata;
contourdata={x0,y0,z0,x1,y1,z1,x2,y2,z2,...}
And I want to sort them by the vector of the z value.
How can I do it in c++?
Like this :
#include <algorithm>
#include <iostream>
#include <vector>
#include <format>
// 3d points have 3 coordinates and
// we need to move those 3 values together when sorting
// It is also good to use "concepts" from real world as
// names in code : so define a struct representing a 3d coordinate.
// (Or use a 3d coordinate type from an existing library)
struct vec_3d_t
{
double x;
double y;
double z;
};
// helper function for outputing the values of one 3d point
// not essential for your problem.
std::ostream& operator<<(std::ostream& os, const vec_3d_t& data_point)
{
os << std::format("({0},{1},{2})", data_point.x, data_point.y, data_point.z);
return os;
}
int main()
{
// std::vector is a (resizable) array
// in this case to hold 3d coordinates
// then initialize the data with some values
// (you will probably get them from somewhere else, e.g. a file)
std::vector<vec_3d_t> contour_data
{
{3.0,4.0,5.0}, // first coordinate
{1.0,2.0,3.0}, // second etc ...
{7.0,8.0,9.0}
};
// this calls the sort algorithm
// using a function to compare two 3d points
// to sort on z only compare z.
std::sort(contour_data.begin(), contour_data.end(), [](const vec_3d_t& lhs, const vec_3d_t& rhs)
{
return lhs.z < rhs.z;
});
// range based for loop over data points
for (const auto& data_point : contour_data)
{
std::cout << data_point << "\n";
}
return 0;
}
I struggled to find a way to use std::sort but you can always drop back the the C qsort stdlib function:
#include <cstdlib>
int compare(const double *A, const double *B) {
return (A[2] <= B[2]) ? -1 : +1;
}
...
const size_t N = contourdata.size() / 3;
qsort(contourdata.data(), N, 3*sizeof(double),
(int (*)(const void *, const void*))compare);
qsort (and mergesort and heapsort) are sort
routines provided by the C standard library that have been around a long time. They are designed to sort data stored in contiguous arrays, but it is the programmers job to specify how the data is laid out and how to order the elements. qsort is not type-safe and generally not preferred, but can handle cases like this one. qsort has three parameters:
A ptr to the base of the array. Note that the ptr type is void * and thus the compiler has no clue about the type of data in the buffer. std::vector provides a data() method that provides a ptr to its internal buffer (which is guaranteed to be contiguous).
The number of elements. Since each element consists of 3 double's we use we use the size of the vector divided by 3.
The size of each element in bytes.
A ptr to a function used for comparing two elements. The arguments to each element are generic ptrs, but since we know they are ptrs to buffers containing doubles we can specify the type in our compare function. Each element is an array of 3 doubles and, since we are using the z-component as the sort key, we compare the doubles at offset 2. We return -1 for "less than" and +1 for "greater" -- this is enough to know how to sort.
Note that when passing the compare function to qsort we cast
it to the function ptr type that it expects to keep the
compiler from issuing a warning.

activity selection problem time limit error [duplicate]

I have a list of structs that I am sorting by one of the members. I am using std::sort with my own comparison function, that part is fine. However, I notice a (very) large performance gap when I change the struct from:
struct square
{
float x;
float y;
float z;
float scale;
float angle;
GLuint texture;
};
to
struct square
{
float x;
float y;
float z;
float scale;
float angle;
GLuint texture;
std::vector <float> color;
};
I have since used an entirely different method, and I realize that using a vector like this is a bad idea (I know the size of array - rgb) but I was wondering why I got the performance hit. I was comparing the z values to sort.
Here is my sorting function and struct list:
std::vector <square> square_list;
//Then add a bunch of squares
bool sort (square a,square b)
{
return a.z < b.z;
}
//Here is the sort that is slow
std::sort (square_list.begin(),square_list.end(),sort);
I wonder if it has anything to do with re-ordering the list of structs as their size is significantly bigger in the second case?
Thanks for any responses.
bool sort (square a,square b)
This copies the structs each time, including the vectors. Vectors are slower to copy than normal arrays. You should use this instead.
bool sort (const square& a, const square& b)
If you are using C++11, you can replace the vector with std::array as the size is constant.
In addition to take parameters as const ref you could use a functor for comparison. That is often faster because functors are more easy to inline.
std::vector <square> square_list;
//Then add a bunch of squares
struct sort
{
bool operator() (const square& a, const square& b) const {
return a.z < b.z;
}
}
std::sort (square_list.begin(),square_list.end(),sort);
sort copy your values every time and std::vector preallocate a bunch of memory. The amount of copy time is bigger
Did you try storing pointers instead of the whole struct in your vector?
std::vector <square*> square_list;
//Then add a bunch of squares
bool sort (square* a,square* b)
{
return a->z < b->z;
}
//Here is the sort that is slow
std::sort (square_list.begin(),square_list.end(),sort);

sorting vectors based on size()

i have a 2-d vector like vector < vector < coordinates > > v( points); where coordinates class is:
class coordinate{
public :
int x;
int y;
coordinate(){
x=0;
y=0;
}
};
and points is 20.
how to sort the individual vectors v[i] based on v[i].size() , ie based on number of coordinates objects pushed in v[i]. ???
1) make a function that compares two vectors based on size:
bool less_vectors(const vector& a,const vector& b) {
return a.size() < b.size();
}
2) sort with it
sort(v.begin(),v.end(),less_vectors);
make a function which you can use whatever attributes to compare the objects and then use STL sort() algorithm to sort the container.
overload the < operation of that class and make it the same as the above function. Then you can use the sort() function provided by the STL containers (like STL list).

C++ member variable aliases?

I'm pretty sure this is possible, because I'm pretty sure I've seen it done. I think it is awesome, but I will gladly accept answers along the lines of "this is a terrible idea because ____".
Say we have a basic struct.
struct vertex
{
float x, y, z;
};
Now, I want to implement aliases on these variables.
vertex pos;
vertex col;
vertex arr;
pos.x = 0.0f; pos.y = 0.5f; pos.z = 1.0f;
col.r = 0.0f; col.g = 0.5f; col.b = 1.0f;
arr[0] = 0.0f; arr[1] = 0.5f; arr[2] = 1.0f;
Ideally the third syntax would be indistinguishable from an array. That is, if I sent arr as a reference parameter to a function expecting an array of floats into which it will store data (eg many of the OpenGL glGet functions), it would work fine.
What do you think? Possible? Possible but stupid?
What I would do is make accessors:
struct Vertex {
float& r() { return values[0]; }
float& g() { return values[1]; }
float& b() { return values[2]; }
float& x() { return values[0]; }
float& y() { return values[1]; }
float& z() { return values[2]; }
float operator [] (unsigned i) const { return this->values_[i]; }
float& operator [] (unsigned i) { return this->values_[i]; }
operator float*() const { return this->values_; }
private:
float[3] values_;
}
Nameless nested structs in a union are not standard C++. This, however, should work:
struct Vertex
{
private:
typedef float Vertex::* const vert[3];
static const vert v;
public:
typedef size_t size_type;
float x, y, z;
const float& operator[](size_type i) const {
return this->*v[i];
}
float& operator[](size_type i) {
return this->*v[i];
}
};
const Vertex::vert Vertex::v = {&Vertex::x, &Vertex::y, &Vertex::z};
EDIT: A little more information. The struct uses an array of 3 pointer-to-data-members to access the data in the overloaded [] operators.
The line "typedef float Vertex::* const vert" means that vert is a pointer to a float member of the Vertex struct. The [3] means that it's an array of 3 of these. In the overloaded operator[], this array is indexed and the pointer-to-data-member is dereferenced and the value returned.
Additionally, this method should work regardless of packing issues - the compiler is free to pad the Vertex structure however it likes and it'll still work just fine. An anonymous union will run into problems if the floats are packed differently.
Use a union?
union vertex
{
struct { float x, y, z; };
struct { float r, g, b; };
float arr[3];
};
I wouldn't recommend it - it will lead to confusion.
Added:
As noted by Adrian in his answer, this union with anonymous struct members is not supported by ISO C++. It works in GNU G++ (with complaints about not being supported when you turn on '-Wall -ansi -pedantic'). It is reminiscent of the pre-pre-standard C days (pre-K&R 1st Edn), when structure element names had to be unique across all structures, and you could use contracted notations to get to an offset within the structure, and you could use member names from other structure types - a form of anarchy. By the time I started using C (a long time ago, but post-K&R1), that was already historical usage.
The notation shown with anonymous union members (for the two structures) is supported by C11 (ISO/IEC 9899:2011), but not by earlier versions of the C standard. Section 9.5 of ISO/IEC 14882:2011 (C++11) provides for anonymous unions, but GNU g++ (4.9.1) does not accept the code shown with -pedantic, identifying "warning: ISO C++ prohibits anonymous structs [-Wpedantic]".
Since the idea will lead to confusion, I'm not particularly concerned that it isn't standard; I would not use the mechanism for this task (and I'd be leery of using anonymous structures in a union even if it was beneficial).
A concern was raised:
The three (x-y-z, r-g-b and the array) do not necessarily align.
It is a union with three elements; the three elements start at the same address. The first two are structures containing 3 float values. There's no inheritance and there are no virtual functions to give different layouts, etc. The structures will be laid out with the three elements contiguous (in practice, even if the standard permits padding). The array also starts at the same address, and subject to 'no padding' in the structures, the elements overlap the two structures. I really don't see that there would be a problem.
References?
template<typename T>
struct vertex {
vertex() :
r(data[0]), g(data[1]), b(data[2]),
x(data[0]), y(data[1]), z(data[2])
{
}
T *operator *() {
return data;
}
const T *operator *() const {
return data;
}
T data[3];
T &r, &g, &b;
T &x, &y, &z;
};
You can get this with a union as others have mentioned. Overloading color and position onto the same structure like this may not be a good idea ( for example, adding two colors usually means you want to saturate to 1.0, whereas adding vectors happens linearly ), but overlaying a float[] on top of them like that is perfectly fine and a well accepted means of interchanging data with GL/DirectX/etc.
I recommend you avoid referring to the same member by different aliases in the same function scope, though, because this will drive you into a nasty hardware stall called a load-hit-store. In particular, avoid this if you can:
vector foo;
foo.x = 1.0f;
return foo[0] + foo[1];
Following structure will have the requested behavior:
struct vertex
{
private:
float data[3];
public:
float &x, &y, &z;
float &r, &g, &b;
vertex() : x(data[0]), y(data[1]), z(data[2]), r(data[0]), g(data[1]), b(data[2]) {
}
float& operator [](int i) {
return data[i];
}
};
I guess you can do some macro magic to get what you want.
But that will look ugly. Why do you want to use same struct, vertex for 3 different types? Why can't you define class for color?
Also keep in mind that vertex and color are not same. If you change something to vertex, that will affect the color also, if you have the same class for both.
I am not sure whether I understood the question correctly. But it looks like you need to overload the operator[] to provide array like access to your struct/class. See the example mentioned here: Operator overloading
I have a template and two Vector classes below, one crazy, one sane. The template implements a simple fixed at compile time array of values. It is designed for subclassing and uses a protected array variable to avoid you having to jump through hoops to access the array. (Some folks might not like such a design. I say, if your subclasses are calling your overloaded operators, coupling might be a good idea.)
The crazy class allows you to have member variables called x, y, z and it acts like an array for calls to glGetFloatV. The sane one just has accessor functions x(), y(), z() and still works with glGetFloatV. You can use either class as a basis for other vector objects you might pass to the OpenGL library. Although the classes below are specific to points, you can obviously just do a search/replace to turn them into a rgb color classes.
The crazy class is crazy because the cost of the syntactic sugar vec.x instead of vec.x() is 3 reference variables. That could take up a lot of space in a large application. Use the simpler sane version.
template <typename T, int N>
class FixedVector {
protected:
T arr[N];
public:
FixedVector();
FixedVector(const T* a) {
for (int i = 0; i < N; ++i) {
arr[i] = a[i];
}
}
FixedVector(const T& other) {
for (int i = 0; i < N; ++i) {
arr[i] = other.arr[i];
}
}
FixedVector& operator=(const T& other) {
for (int i = 0; i < N; ++i) {
arr[i] = other.arr[i];
}
return *this;
}
T* operator&() { return arr; }
const T* operator&() const { return arr; }
T& operator[](int ofs) {
assert(ofs >= 0 && ofs < N);
return arr[ofs];
}
const T& operator[](int ofs) const {
assert(ofs >= 0 && ofs < N);
return arr[ofs];
}
};
class CrazyPoint : public FixedVector<float, 3> {
public:
float &x, &y, &z;
CrazyPoint()
: x(arr[0]), y(arr[1]), z(arr[2])
{ arr[0] = arr[1] = arr[2] = 0.0; }
CrazyPoint(const float* a)
: x(arr[0]), y(arr[1]), z(arr[2])
{
arr[0] = a[0];
arr[1] = a[1];
arr[2] = a[2];
}
CrazyPoint(float a, float b, float c)
: x(a), y(b), z(c)
{
arr[0] = a;
arr[1] = b;
arr[2] = c;
}
};
class SanePoint : public FixedVector<float, 3> {
public:
float& x() { return arr[0]; }
float& y() { return arr[1]; }
float& z() { return arr[2]; }
SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
SanePoint(float a, float b, float c)
{
arr[0] = a;
arr[1] = b;
arr[2] = c;
}
};
// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);
Bad idea in my opinion, at least for the example given: the downside is that, for just about any solution to this, you're probably going to be able to freely assign "rgb" instances to/from "xyz" instances, which is probably rarely sensible or correct. ie you risk giving up some useful type safety.
Personally, for the example you give, I'd subclass rgb and xyz types from a base boost::array<float,3> or similar. So both of them inherit operator[], can be passed to functions expecting arrays, and passed with more type safety to things expecting colours/coordinates. It's often you want to treat an xyz or an rgb as an array, but rare you want to treat an xyz as an rgb or vice-versa. (rgb IS-A array: OK. xyz IS-A array: OK. rgb IS-A xyz ???? I don't think so!)
Of course that means access to x,y,z & r,g,b needs to be by accessor (forwarding to the appropriate operator[](...) ) rather than direct to the member. (You'd need C#'s properties for that).
You can try adding references to variables, like this:
struct test {
float x, y, z;
float &r, &g, &b;
test() : r(x), g(y), b(z) {}
};
But your structure gets bigger (from 12 bytes to 40 bytes).
To use [] on it, use overloading of operator[], as mentioned before.
Just a warning about using reference members pointing to value members. You need to define a copy constructor (and possibly also assignment operator), if you ever copy such an object (like transfer it by value). The default copy constructor will leave you with a copy whose reference members point to the value members of the original object, not the ones of the new object. This is certainly not something you want.
Considering you also end up with larger objects, as already pointed out, I think using accessor methods is to be preferred over reference members.
I think the poster was looking for something very simple, with no performance overhead - as you would want with something like a 3D vector class. So adding virtual functions (vtable indirection cost), additional members (memory cost), unions (each new name may require a recompile of all users), or even preprocessor magic (increased program size, cross-type equivalency) is undesirable.
Real world use case would be to take a templated Vector3 class (which could be double-based or float-based) and apply it to other scenarios in a user-friendly manner. It is likely defined with [x, y, z] members, but if you want to use it for rotations, you might want [psi, theta, phi], for speeds [dx, dy, dz], etc.
For the entire type, you can use the following to alias it at compile time:
using Rotation3 = Vector3;
But there appears to be nothing as simple or performant that you can do for aliasing the underlying variables, right?