How to memcpy std::map values to a pointer?

Started by
6 comments, last by Bregma 4 years, 9 months ago

I have a std::map<int, Point> keyed by the points id. I need to do the equivalent of a memcpy into a pointer like the following.


struct Point {
    float x, y, z;
    float nx, ny, nz;
};

// ...

std::map<int, Point> meshA = submesh.at(2);

Point* points = reinterpret_cast<Point*>(OGRE_MALLOC_SIMD(sizeof(Point) * totalPoints(), Ogre::MEMCATEGORY_GEOMETRY));

// memcpy into points?
  

After allocating the memory, how does one do the equivalent of a memcpy of std::map<int, Point> into 'Point* points'? I have to populate this pointer (Point *) which is the type my engine API takes.

Advertisement

Do you just want the 'Point' instances from the map, without the IDs? [Edit: I'm guessing that's the case based on the use of 'Point *', but it might still be worth clarifying that.] And does order matter? (E.g. do you want the points ordered by ascending ID?)

Yeah, I should have clarified that.

No, the point id's wouldn't be a part of it. Just the point structures. Yes, order does matter.

Assuming the order you want is by ascending ID, then I think you'll need to iterate over the map and process each 'Point' instance one at a time (either implicitly or explicitly - there are various ways you could express it using standard library features).

There may be other issues involved, such as padding, alignment, reinterpret_cast vs static_cast, and so on, but I don't know much about the context you're working in, so I won't comment on those issues. It sounds like the key question though is how to extract the 'Point' instances from the map, and I think the answer is that, one way or another, it needs to be done one at a time.

I think you need to question why you have an std::map<> from int to Point in the first place... but assuming it's working fine for you, what's wrong with...


void populate_raw_array(Point * &dest, int & maxN, std::map<int,Point> source const) {
  if( maxN > source.size() ) maxN = source.size();
  for (auto dp = dest, i = source.begin(), n = maxN; n != 0; ++dp, ++i, --n) {
    *dp = i->second;
  }
}

// Usage...
Point buffer[256];
int size = 256;
populate_raw_array(buffer, size, my_map_of_points);
// buffer[0] through buffer[size], exclusive, now have points in.

 

RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.

You could way more simple store all your points in memory and have the map just point to an Integer to Point-Pointer pair instead of to just the Point instance itself

Using SIMD implies you need the points in contiguous memory, which a map does not have.

You could use std::transform() from the map to the SIMD memory using a simple lambda to get the second member of the map pair.


transform(begin(meshA), end(meshA),
          back_inserter(points),
          [](map<int,Point>::value_type const& mp) -> Point
              { return mp.second; });

You could also use a loop.


auto p = points;
for (auto const& mp: meshA)
    *p++ = mp.second;

There is no more efficient way.

Note that std::map is a sorted associative container, so no fancy sorting is necessary, unless your desired sort order differs from the one you're sorting the map by.  In that case, std::sort is your best friend, but you might also consider why you're using a sorted associative container in the first place if you're not using the sort order of the container.

Stephen M. Webb
Professional Free Software Developer

This topic is closed to new replies.

Advertisement