#include <iostream> 
#include <array>
#include <vector>
#include <map>

using TIndices  = std::vector<int>;
using TFace     = std::array<int, 3>;
using TFaces    = std::vector<TFace>;
using TVertex   = std::array<float, 3>;
using TVertices = std::vector<TVertex>;

void GenerateAdjacencies( const TVertices &vertices, const TFaces &faces, TIndices &adj )
    {
        // associate each geometric vertex position with an unique ID
        std::vector<int>      uniqueMap;
        std::map<TVertex,int> tempUniqueVertices;
        int uniqueIndex = 0;
        for ( size_t vI = 0; vI < vertices.size(); ++ vI )
        {
            auto vIt = tempUniqueVertices.find( vertices[vI] );
            if ( vIt == tempUniqueVertices.end() )
            {
                tempUniqueVertices[ vertices[vI] ] = uniqueIndex;
                uniqueMap.push_back( uniqueIndex );
                uniqueIndex ++;
            }
            else
                uniqueMap.push_back( vIt->second );
        }
        tempUniqueVertices.clear();

        // find all edges and associate the edge with all the points, which form a triangle with it. 
        std::map< std::tuple<int, int>, std::vector<int> > edges;
        for ( auto & f : faces )
        {
          for ( int pI = 0; pI < 3; ++ pI )
          {
            int edgeU[2]{ uniqueMap[f[pI]], uniqueMap[f[(pI+1) % 3]] };
            int i0 = edgeU[0] < edgeU[1] ? 0 : 1;
            edges[{ edgeU[i0], edgeU[1-i0] }].push_back( f[(pI+2) % 3] );
          }
        }

        // create the adjacencies
        for ( auto & f : faces )
        {
            for ( int pI = 0; pI < 3; ++ pI )
            {
                int edgeU[2]{ uniqueMap[f[pI]], uniqueMap[f[(pI+1) % 3]] };
                int   i0   = edgeU[0] < edgeU[1] ? 0 : 1;
                auto &adjs = edges[{ edgeU[i0], edgeU[1 - i0] }];
                int   adjI = adjs.size() > 1 && adjs[0] == f[(pI+2) % 3] ? 1 : 0;
                adj.push_back( f[pI] );
                adj.push_back( adjs[adjI] );
            }
        }
    }

int main( void )
{
    TVertices pt{
        {  1.0f, -1.0f, -1.0f },
        {  1.0f, -1.0f,  1.0f },
        { -1.0f, -1.0f,  1.0f },
        { -1.0f, -1.0f, -1.0f },
        {  1.0f,  1.0f, -1.0f },
        {  1.0f,  1.0f,  1.0f },
        { -1.0f,  1.0f,  1.0f },
        { -1.0f,  1.0f, -1.0f }
    };

    TFaces indices{
        { 2, 3, 4 },
        { 8, 7, 6 },
        { 5, 6, 2 },
        { 6, 7, 3 },
        { 3, 7, 8 },
        { 1, 4, 8 },
        { 1, 2, 4 },
        { 5, 8, 6 },
        { 1, 5, 2 },
        { 2, 6, 3 },
        { 4, 3, 8 },
        { 5, 1, 8 }
    };

    TVertices vertices;
    TFaces    faces;
    int vI = 0;
    for ( auto &f : indices )
    {
      for ( int i = 0; i < 3; ++ i )
        vertices.push_back( pt[f[i]-1] );
      faces.push_back( { vI++, vI++, vI++ } );
    }

    TIndices adj;
    GenerateAdjacencies( vertices, faces, adj );

    for ( size_t fI = 0; fI < faces.size(); ++ fI )
    {
        std::cout << "(" << faces[fI][0] << ", " << faces[fI][1] << ", " << faces[fI][2] << ") -> ";

        for ( size_t aI = 0; aI < 6; ++ aI )
          std::cout << adj[fI*6+aI] << " ";
        std::cout << std::endl;
    }

    return 0;
}