1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
#include <iostream>
#include <string>
#include <vector>
struct record
{
int year ;
std::string province ;
std::string degree ;
std::string gender ;
};
// a property maps the key to a collection of pointers to records
template < typename KEY > struct property
{
KEY key ;
std::vector< const record* > recs ;
};
// just a collection of properties
// map etc. are not allowed, so we use vectors everywhere
template < typename KEY > struct property_collection
{
std::vector< property<KEY> > items ;
// add this record with this key to the collection
void add( const KEY& key, const record* r )
{
if( r == nullptr ) return ;
// if a property with this key is found, add the record to its vector and return
// we are not keeping the keys in sorted order; so a simple sequential search
for( auto& prop : items ) if( prop.key == key ) return prop.recs.push_back(r) ;
// we did not find a property with this key;
// so we create a new one with this key and just this one record in the vector
items.push_back( { key, {r} } ) ;
}
};
// a namespace instead of a class with all static members
namespace report_gen
{
std::vector< const record* > records ;
property_collection<int> years ;
property_collection<std::string> provinces ;
// etc
void populate()
{
for( const record* r : records ) if(r) // for all non-null pointers in records
{
years.add( r->year, r ) ; // add to the appropriate years property
provinces.add( r->province, r ) ; // add to the appropriate provinces property
// etc.
}
}
}
int main()
{
// create a set of records for testing
// for this simple test, we use an array to hold the records by value because pointers
// to items in a vector may get invalidated if the vector is modified
const record data[]
{
{ 2000, "AB", "Bachelor's", "M" },
{ 2005, "DE", "Bachelor's", "F" },
{ 2010, "CA", "Bachelor's", "F" },
{ 2015, "AB", "Masters's", "M" },
{ 2000, "AB", "Bachelor's", "M" },
{ 2005, "DE", "Master's", "F" },
{ 2010, "DE", "Master's", "U" },
{ 2015, "AB", "Masters's", "M" },
{ 2000, "AB", "Bachelor's", "M" },
{ 2005, "DE", "Bachelor's", "F" },
{ 2010, "AB", "Doctorate", "F" },
{ 2015, "AB", "Masters's", "M" },
{ 2010, "CA", "Diploma", "M" },
};
// add pointers to the records to report_gen
for( const record& rec : data ) report_gen::records.push_back( std::addressof(rec) ) ;
// populate the property collections in report_gen
report_gen::populate() ;
// generate a report: list of all records for the year 2010
// note that the actual reports to be generated would be members of report_gen.
for( const auto& prop : report_gen::years.items )
{
if( prop.key == 2010 ) // if it is for year 2010
{
std::cout << "year 2010: found " << prop.recs.size() << " records\n-----------\n" ;
for( const record* r : prop.recs ) // print all the records in the vector
std::cout << r->year << ' ' << r->province << ' ' << r->degree << ' ' << r->gender << '\n' ;
}
}
// generate another sample report: count of students with gender F in province DE
int n = 0 ;
for( const auto& prop : report_gen::provinces.items )
{
if( prop.key == "DE" ) // if it is for the province DE
for( const record* r : prop.recs ) n += r->gender == "F" ;
}
std::cout << "\nthere are " << n << " records with gender == \"F\" in province \"DE\"\n" ;
}
|