#include <mpi.h>
#include <sstream>
#include <numeric>
#include <vector>

int main(int argc, char **argv)
{
    MPI_Init(&argc, &argv);
    int rank;
    int size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    int name_length;
    char name[1024];
    MPI_Get_processor_name(name, &name_length);
    name[name_length] = 0;
    // transmit the trailing 0, too
    name_length += 1;

    std::vector<int> name_lengths(size);
    MPI_Allgather(&name_length, 1, MPI_INT, &name_lengths[0], 1, MPI_INT, MPI_COMM_WORLD);

    std::vector<int> offsets(size + 1, 0);
    std::partial_sum(name_lengths.begin(), name_lengths.end(), offsets.begin() + 1);

    std::string receive_buffer(offsets.back(), 0);
    MPI_Allgatherv(
        name, name_length, MPI_CHAR,
        &receive_buffer[0], &name_lengths[0], &offsets[0], MPI_CHAR,
        MPI_COMM_WORLD);

    // tokenize names
    std::vector<std::string> names;
    {
        std::istringstream name_stream(receive_buffer);
        std::string temp_name;
        while (std::getline(name_stream, temp_name, char(0))) {
            names.push_back(temp_name);
        }
    }

    if (rank == 0) {
        for (int i = 0; i < size; ++i) {
            std::cout << "names[" << i << "] = " << names[i] << "\n";
        }
    }

    MPI_Finalize();
}
