6

I have serialized an array of floats into a RepeatedField using Google's Protcol Buffers.

When deserializing the data I use another settings class to hold the information in a more appropriate form for my game classes. A static CreateFrom method extracts and converts the data.

class VoxelTerrainSettings
{
public:
    std::vector<int> indices;
    btAlignedObjectArray<btVector3> vertices;

    VoxelTerrainSettings(void);
    ~VoxelTerrainSettings(void);

    static VoxelTerrainSettings CreateFrom(const VoxelTerrainProtoBuf::VoxelTerrainSettings &settings)
    {
        VoxelTerrainSettings s;

        int numIndices = settings.indices().size();

        s.indices.reserve(numIndices);

        for (int i = 0; i < numIndices; ++i)
        {
            s.indices.push_back(settings.indices().Get(i));
        }

        int numVertices = settings.vertices().size();

        s.vertices.reserve(numVertices);

        int v = 0;

        for (int i = 0; i < numVertices; ++i)
        {
            s.vertices.push_back(btVector3(settings.vertices().Get(v++), settings.vertices().Get(v++), settings.vertices().Get(v++)));
        }

        return s;
    }

    //VoxelTerrain Load();
};

However, the current method for extracting all the elements from the RepeatedField doesn't seem very elegant.

I've tried adopting a more efficient approach but they both throw out of range errors.

std::copy(settings.vertices().begin(), settings.vertices().end(), vv.begin());
std::copy(&settings.vertices().Get(0), &settings.vertices().Get(settings.vertices().size() - 1), &vv[0]);

What methods could I use to make element extraction more efficient?

user1423893
  • 766
  • 4
  • 15
  • 26
  • Side note: C++ doesn't specify the order of parameter evaluation, so your 3 `v++` expressions could be evaluated in any order at the whim of the optimizer, leading to hard-to-trace down bugs after a future code change or compiler upgrade. – Edward Brey Jul 26 '17 at 14:56

2 Answers2

9

std::copy uses std::front_inserter/std::back_inserter iterator types for inserting values into containers Try the following:

// inserting into list/deque
std::copy(settings.vertices().begin(), settings.vertices().end(), std::front_inserter(vv));
// inserting into vector
std::copy(settings.vertices().begin(), settings.vertices().end(), std::back_inserter(vv)); 
DarkWanderer
  • 8,739
  • 1
  • 25
  • 56
  • 7
    For a vector, `front_inserter` is slow, since for each insertion, it has to bump back all other elements in the vector. – Edward Brey Jul 26 '17 at 15:07
4

Fastest is to reserve space up front, and then transform in one loop to optimize caching.

s.indices.reserve(settings.indices().size());
s.vertices.reserve(settings.vertices().size());

for (auto& vertex : settings.vertices()) {
   s.indicies.push_back(...);
   s.verticies.push_back(...);
}
Edward Brey
  • 40,302
  • 20
  • 199
  • 253