Maintaining a unique set of elements according to various C ++ STL criteria

I need to develop a component that will have more than 100,000 class instances. And I want to create a report based on different criteria (participants) of a particular class. for example, Employee class with data field identifier, names, addr, phoneno. generation report will be based on


  • names_ascending
  • names_descending
  • addr_ascending
  • phoneno_asceding
  • unique_names
  • unique_addr
  • unique_phoneno

Initialization of instances for each call is very slow, as it is a linear operation for a large number of instances and requires a sorting mechanism.

, . , . , . , .

class Employee
{
    int    m_id;
    string m_name;
    string m_addr;
    string m_phone;

public:
    Employee(int id, string name, string addr, string phone) : 
         m_id(id), m_name(name), m_addr(addr), m_phone(phone) { }

    int    id()      const { return m_id;    }
    string name()    const { return m_name;  }
    string addr()    const { return m_addr;  }
    string phoneno() const { return m_phone; }
};

//custom predicate for std containers
struct IDComparator
{
    bool operator() (const Employee* e1, const Employee* e2 )
    {
       return e1->id() < e2->id();
    }
};

struct NameComparator
{
    bool operator() (const Employee* e1, const Employee* e2 )
    {
       return e1->name() < e2->name();
    }
}

struct AddressComparator
{
    bool operator() (const Employee* e1, const Employee* e2 )
    {
       return e1->addr() <  e2->addr();
    }
};

struct PhoneComparator
{
    bool operator() (const Employee* e1, const Employee* e2 )
    {
       return e1->phoneno() < e2->phoneno();
    }
};


//Class which holds huge number of employee instances
class Dept
{
private:
    typedef set<Employee*, IDComparator> EMPID; //unnique id
    typedef EMPID::iterator EMPID_ITER;

    typedef multiset<const Employee*, NameComparator> EMPNAME;   // for sorted names
    typedef EMPNAME::iterator NAME_ITER;

    typedef multiset<const Employee*, AddressComparator> EMPADDR; // for sorted addr
    typedef EMPADDR::iterator ADDR_ITER;

    typedef multiset<const Employee*, PhoneComparator> EMPPHONE;  // for sorted phoneno
    typedef EMPPHONE::iterator PHONE_ITER;

private:
    EMPID    m_empids;
    EMPNAME  m_names ;
    EMPADDR  m_addr;
    EMPPHONE m_phoneno;

public:
    Dept() { }
    ~Dept() { //delete the instances of employees }

    void add(Employee* e) 
    {
        EMP_ITER iter = m_empids.insert(e).first;
        const Employee* empptr = &*iter;
        m_names.insert(empptr);    // adds employee pointer to name multimap
        m_addr.insert(empptr);     // adds employee pointer to addr multimap
        m_phoneno.insert(empptr);  // adds employee pointer to phone multimap
    }


    void print_emp_dtls()       const; //prints all the emp dtls iterating though EMPID 

    void print_unique_names()   const; //iterate EMPNAME & use upperbound & lowerbound, prints unique names 
    void print_asc_name()       const; //iterate EMPNAME & prints all names in ascending order
    void print_desc_name()      const; //back iterate EMPNAME & prints all names in descending order

    void print_unique_adrr()    const; //iterate EMPADDR & use upperbound & lowerbound, prints unique address
    void print_asc_addr()       const; //iterate EMPADDR & prints all addr in ascending order
    void print_desc_addr()      const; //back iterate EMPADDR & prints all address in descending order

    void print_unique_phoneno() const; //iterate EMPPHONE & use upperbound & lowerbound,prints unique phoneno
    void print_asc_phoneno()    const; //iterate EMPPHONE & prints all phoneno in ascending order
    void print_desc_phoneno()   const; //back iterate EMPPHONE & prints all phoneno in     };
+3
3

Boost.Multi_index . , . , "", "" . , :

struct user_t
{
    string id, name, email;
    int age;
    friend ostream& operator<<(ostream& output_stream, const user_t& user)
    {
        return output_stream
            << user.id    << " "
            << user.name  << " "
            << user.age   << " "
            << user.email << "\n";
    }
    friend istream& operator>>(istream& input_stream, user_t& user)
    {
        return input_stream >> user.id >> user.name >> user.age >> user.email;
    }
};

, , , , . , . - ! :

struct by_id    { };
struct by_name  { };
struct by_age   { };
struct by_email { };

" " :

typedef multi_index_container<
    user_t,
    indexed_by
    <
      ordered_unique<tag<by_id>, member<user_t, string, &user_t::id> >,
      ordered_non_unique<tag<by_name>, member<user_t, string, &user_t::name> >,
      ordered_non_unique<tag<by_age>, member<user_t, int, &user_t::age> >,
      ordered_non_unique<tag<by_email>, member<user_t, string, &user_t::email> >
    >
> user_db;

, . , :

indexed_by
<
  ordered_unique<tag<by_id>, member<user_t, string, &user_t::id> >,
  ordered_non_unique<tag<by_name>, member<user_t, string, &user_t::name> >,
  ordered_non_unique<tag<by_age>, member<user_t, int, &user_t::age> >,
  ordered_non_unique<tag<by_email>, member<user_t, string, &user_t::email> >
>

, . , , . ( ), , . "" . !

user_db, std::multi_set! , ;) , Seriolized users indecies:

 user_db load_information()
{
    ifstream info_file("information.txt");
    user_db db;
    user_t user;
    while(info_file >> user)
        db.insert(user);
    return db;
}
template <typename index_t>
void save_information_by(ostream& output_stream, const index_t& index)
{
    ostream_iterator<user_t> serializer(output_stream);
    copy(index.begin(), index.end(), serializer);
}
int main()
{
    ofstream
        by_id_file("by_id.txt"),
        by_name_file("by_name.txt"),
        by_age_file("by_age.txt"),
        by_email_file("by_email.txt");
    user_db db = load_information();
    // You see why we created the tags,
    // if we didn't we had to specify the index like the following:
    // const auto& name_index  = db.get<by_name>(); ==
    // const auto& name_index  = db.get<1>();
    const auto& id_index    = db.get<by_id>();
    const auto& name_index  = db.get<by_name>();
    const auto& age_index   = db.get<by_age>();
    const auto& email_index = db.get<by_email>();
    save_information_by(by_id_file, id_index);
    save_information_by(by_name_file, name_index);
    save_information_by(by_age_file, age_index);
    save_information_by(by_email_file, email_index);
}
+3

Boost.MultiIndex:

Boost Multi-Index Containers multi_index_container, .

+5

boost::multi_index . boost::multi_index_contaier, , .

+2

Source: https://habr.com/ru/post/1780426/


All Articles