Fill extern std::array fileds one by one

I have the following code

   //Block.h
    enum class BlockType : uint8_t {
    BlockType_Air = 0,
    BlockType_Default = 1,
    BlockType_Grass = 2,
    BlockCount
};

struct BlockTextureData {
    std::string top;
    std::string bottom;
    std::string left;
    std::string right;
    std::string front;
    std::string back;
};

extern std::unordered_map<BlockType, BlockTextureData*> BlockTextures;

   //Block.cpp
std::unordered_map<BlockType, BlockTextureData*> BlockTextures = {
    {BlockType::BlockType_Default, new BlockTextureData{"UV","UV","UV","UV","UV", "UV"}},
    {BlockType::BlockType_Grass, new BlockTextureData{"GrassTop","GrassBottom","GrassSide","GrassSide","GrassSide", "GrassSide"}}
};

Issue is the map is accessed thousands of times whitc causes it to rack up quite a performance cost, as its makes itself a bout 20% of the runtime of the given functions its in. I head you can use enum values as keys for arrays, so i wanted to replace std::unordered_map with std::array. But when i tried to populate the array i got error that its incomplete.

The thing is all enum values dont need a corresbonding object in BlockTexturers and can be null. So i would like to define the values one by one. Is there a way to do this ?

my attempt

//block.h
extern std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures;

//block.cpp
std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures[static_cast<size_t>(BlockType::BlockType_Default)] = new BlockTextureData{"UV","UV","UV","UV","UV", "UV"};

std::array<BlockTextureData*, static_cast<size_t>(BlockType::BlockCount)> BlockTextures[static_cast<size_t>(BlockType::BlockType_Grass)] = new BlockTextureData{"GrassTop","GrassBottom","GrassSide","GrassSide","GrassSide", "GrassSide"};

>Solution :

You could use a helper function:

static auto makeBlockTextures() {
    std::array<BlockTextureData*, (std::size_t)BlockType::Count> arr{};
    arr[(std::size_t)BlockType::Default] = new BlockTextureData{ /* ... */ };
    arr[(std::size_t)BlockType::Grass]   = new BlockTextureData{ /* ... */ };
    return arr;
};

std::array<BlockTextureData*, (std::size_t)BlockType::Count>
    BlockTextures = makeBlockTextures();

or an immediately invoked lambda:

std::array<BlockTextureData*, (std::size_t)BlockType::Count> BlockTextures = []()
{
    std::array<BlockTextureData*, (std::size_t)BlockType::Count> arr{};
    arr[(std::size_t)BlockType::Default] = new BlockTextureData{ /* ... */ };
    arr[(std::size_t)BlockType::Grass]   = new BlockTextureData{ /* ... */ };
    return arr;
}();

Leave a Reply