#include <cstring>
#include <cstdlib>
#include <cassert>
#include <cstdint>

#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>

template <typename T>
class TrivialAllocator {
    size_t default_allocate;
    size_t allocated;
    
    size_t const size;
    T * elements;
    
public:    
    TrivialAllocator( size_t size, size_t default_allocate = 1 ) 
    : default_allocate( default_allocate ),
      allocated( 0 ), size( size ),
      elements( (T*)malloc(sizeof(T)*size) )
    { }
    
    ~TrivialAllocator() { free( elements ); }
    
    T * allocate( size_t count ) {
        assert( allocated + count < size );
        T * ret = elements + allocated;
        allocated += count;
        return ret;
    }
    
    T * allocate() {
        return allocate( default_allocate );
    }
};

struct BasicStudentInfo {
    char * name;
    char * id;
    
    BasicStudentInfo( char const * name,
                               char const * id,
                               TrivialAllocator<char> & alloc ) 
    : name( alloc.allocate(strlen(name)+1) ),
      id( alloc.allocate(strlen(id)+1) )
    {  
        strcpy( this->name, name );
        strcpy( this->id, id );
    }
    
    virtual void print( std::ostream & output ) {
        output << "name : " << name << ", id : " << id;
    }
};

struct AdvanceStudentInfo : BasicStudentInfo {
    char * sex;
    char * school;
    
    AdvanceStudentInfo( char const * name,
                                    char const * id,
                                    char const * sex,
                                    char const * school, 
                                    TrivialAllocator<char> & alloc ) 
    : BasicStudentInfo( name, id, alloc ),
      sex( alloc.allocate(strlen(sex)+1) ),
      school( alloc.allocate(strlen(school)+1) )
    {
        strcpy( this->sex, sex );
        strcpy( this->school, school );
    }
    
    virtual void print( std::ostream & output ) {
        output << "name : " << name << ", id : " << id 
                   << ", sex : " << sex << ", school : " << school;
    }    
};

template <typename Score>
struct ScoreEntry {
    BasicStudentInfo * info;
    Score * scores;
    
    ScoreEntry( BasicStudentInfo * info, Score * scores ) 
    : info( info ), scores( scores )
    {  }
};

template <typename Score>
class Transcript {
    
    TrivialAllocator<char> char_alloc;
    TrivialAllocator<Score> score_alloc;
    TrivialAllocator<AdvanceStudentInfo> info_alloc;
    
    std::vector< ScoreEntry<Score>> entries;
    size_t score_count;
    
public:    
    Transcript( size_t score_count ) 
    : char_alloc( 100 ),
      score_alloc( 100, score_count ),
      info_alloc( 100 ),
      score_count( score_count )
    { }
    
    void read( std::istream & input ) {
        using namespace std;
        string name, id;
        while( input ) {
            if( !(input >> name >> id) ) break;
            BasicStudentInfo * info = info_alloc.allocate();
            new (info) BasicStudentInfo( name.c_str(), id.c_str(), char_alloc );
            
            Score * scores = score_alloc.allocate();
            for( size_t i = 0; i != score_count; ++i )
                input >> scores[ i ];
            
            entries.push_back( ScoreEntry<Score>(info, scores) );
        }
    }
    
    void print( std::ostream & output ) {
        for( auto entry = entries.begin(); entry != entries.end(); ++entry ) {
            entry->info->print( output );
            
            output << ", scores : ";
            std::copy( entry->scores, entry->scores + score_count,
                            std::ostream_iterator<Score>(output, " ") );
            output << std::endl;
        }
    }
};

int main() {
    
    using namespace std;
    
    Transcript<int> transcript( 3 );
    
    istringstream input(  "Alice  A01  99 85 90\nAdam  A02  77 80 91\n" );
    transcript.read( input );
    transcript.print( cout );
    
}
