0

I am wondering what are the efficient ways of searching a map for user groups. Assume we have got a map of specific objects of which a user group has got permission to access it.

Would it be better generate another map for each user group to be able to access faster?

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
xpath
  • 33
  • 4

1 Answers1

0

It really depends on your expected usage patterns. You have three types of entities:

  1. objects
  2. groups
  3. users

For simplifying things, let's concentrate just on the latter 2.

  1. Are you optimizing the case where, given a group, you want to check if a specific user belongs to it?

  2. Is removing a user from all groups efficiently important? Should it affect other users in a multithreading environment? Does it have to be atomic if so?

  3. Are you optimizing for size or speed?

Depending on the answers (to these and probably many other questions), different solutions may work for you.

For example, consider the following:

#include <unordered_map>
#include <unordered_set>

using user_id_t = std::size_t;
using group_id_t = std::size_t;

using group_to_users_t = std::unordered_map<group_id_t, std::unordered_set<user_id_t>>;

int main() {
    group_to_users_t authorized;

    authorized[3].insert(20);
}

This uses an std::unordered_map to match each group to an std::unordered_set of users. It shows how to insert user 20 into group 3. It is very efficient in querying if user 20 belongs to group 3. It is very inefficient for answering what are the groups to which user 20 belongs.

Conversely, consider the following:

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>

using namespace boost;
using namespace boost::multi_index;

struct permission {
    std::size_t m_group_id;
    std::size_t m_user_id;
};

using  permissions_t = multi_index_container<
    permission,
    indexed_by<
        ordered_non_unique<member<permission, decltype(permission{}.m_user_id), &permission::m_user_id>>,
        ordered_non_unique<member<permission,std::size_t,&permission::m_group_id>>>>;

int main() {
    permissions_t permissions;

    permission foo{3, 20};
    permissions.insert(foo);
}

It uses a boost::multi_index::multi_index_container to simultaneously map a permission by both group and user. It therefore allows efficient access by both group and user; conversely, it is a more complex object, with higher space and time overheads.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185