2

Im working with boost::icl::interval_map that works perfectly but i want this container to be stored in shared memory. Does boost provide support for storing boost::icl containers in shared memory

    using namespace std;
    using namespace boost::icl;

    struct IFM {
           std::string destinationGroup;
           int priority;
           IFM()
           {
               destinationGroup= "";
               priority = 0;

           }

           IFM(const std::string& d, const int& p)
                 {
                     destinationGroup= d;

                     priority = p;

                 }


           IFM& operator +=(const IFM& right)
            {
                destinationGroup+= right.destinationGroup;
                priority += right.priority;
                return *this;
            }


        bool operator <(const IFM& left) const {
            if(priority <  left.priority)
                return true;
        }

        bool operator ==(const IFM& left) const {
            return destinationGroup== left.destinationGroup
                    && priority == left.priority;

        }

    };

    typedef std::set<IFM> guests;


    void boost_party()
    {
        interval_map<double, guests> party;

        IFM i = {"123", 1};
        IFM j = {"124", 1};
        IFM k = {"126", 2,};
        IFM l = {"128", 1};
        IFM m = {"129", 1};
        IFM n = {"130", 1};

        guests ii;
        ii.insert(i);

        guests jj;
        jj.insert(j);

        guests kk;
        kk.insert(k);

        guests ll;
        ll.insert(l);


        guests mm;
        mm.insert(m);

        party.add(make_pair(interval<double>::closed(12345600000,12345699999), guests(ii)));
        party.add(make_pair(interval<double>::closed(32100000000,32199999999), guests(jj)));
        party.add(make_pair(interval<double>::closed(42000000000,42999999999), guests(ll)));
        party.add(make_pair(interval<double>::closed(42101000000,42101099999), guests(kk)));
        party.add(make_pair(interval<double>::closed(67000000000,67999999999), guests(mm)));

        interval_map<double, guests>::const_iterator it;
        it = party.find(42101035898);

        if (it != party.end()) {
            interval<double>::type when = it->first;
            guests who = (*it++).second;
            cout << who.size() << endl;
            for (auto it2 : who) {
                    cout << when << ": " << it2.destinationGroup<< endl;
            }
        }
    }

int main() {
    boost_party();
    return 0;
}

Gives me following output which is expected Now i m trying to put a simple map interval_map in shared memory first but my code never compiles

boost::interprocess::managed_shared_memory segment(
     boost::interprocess::create_only, "MySharedMemory" //segment name
     , 65536);

     typedef int KeyType;
     typedef int MappedType;
     typedef pair<int,int> keyvalue;

     typedef boost::interprocess::allocator<keyvalue, boost::interprocess::managed_shared_memory::segment_manager>
     ShmemAllocator;

     ShmemAllocator alloc_inst (segment.get_segment_manager());

     typedef boost::icl::interval_map<int, int, boost::icl::partial_absorber, std::less, boost::icl::inplace_plus,boost::icl::inter_section, boost::icl::discrete_interval<int, std::less>, ShmemAllocator> MyMap;

Give following error

error: type/value mismatch at argument 8 in template parameter list for ‘template class Compare, template class Combine, template class Section, class Interval, template class Alloc> class boost::icl::interval_map’ typedef boost::icl::interval_map, ShmemAllocator> MyMap;

error: expected a class template, got ‘ShmemAllocator {aka boost::interprocess::allocator, boost::interprocess::segment_manager, boost::interprocess::iset_index> >}’

error: invalid type in declaration before ‘;’ token

Asna
  • 108
  • 8

1 Answers1

2

For now, the compiler error indicates that you're passing a type as a template argument, where a (variadic) template template argument was expected.

You could technically achieve that using C++11 template aliasing¹:

template <typename T> using allocator = bip::allocator<T, smgr>;
template<typename T>  using set       = std::set<T, allocator<T> >;

template <typename Domain, typename Codomain>
using basic_map = icl::interval_map<Domain, Codomain,
        icl::partial_absorber, std::less, icl::inplace_plus, icl::inter_section, icl::discrete_interval<int, std::less>,
        allocator
    >;

However, it will not lead to working code as I've found in my livecoding session. The problem is that clearly Boost ICL doesn't currently support stateful allocators.

This means that not all constructors take an allocator instance to pass in the required state.

Sadly, this means that only a hacky custom allocator could conceivably work, where the custom allocator would refer to your shared memory segment by a global reference.

Demo

Here's a demo that shows proof-of-concept with such a global-segment allocator:

Live On Coliru

#include <boost/icl/interval_map.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <iostream>
#include <vector>
#include <set>

namespace bip = boost::interprocess;
namespace icl = boost::icl;

namespace shared {
    using segment = bip::managed_mapped_file;
    using smgr    = segment::segment_manager;
}

namespace {

    static bip::managed_mapped_file global_mm(bip::open_or_create, "./demo.bin", 1ul<<20);
    static bip::allocator<void, shared::smgr> global_alloc(global_mm.get_segment_manager());

    template <class T> struct SimpleAllocator : std::allocator<T> { // inheriting the nested typedefs only
        typedef T value_type;

        SimpleAllocator() : _alloc(global_alloc) {}
        template <class U> 
            SimpleAllocator(const SimpleAllocator<U> &other) : _alloc(other._alloc) {}

        T* allocate(std::size_t n)           { return std::addressof(*_alloc.allocate(n)); }
        void deallocate(T *p, std::size_t n) { _alloc.deallocate(p, n); }

        // optionals
        template <typename Other> struct rebind { typedef SimpleAllocator<Other> other; }; 
        bip::allocator<T, shared::smgr> _alloc;
    };

    template <class T, class U> bool operator==(const SimpleAllocator<T> &, const SimpleAllocator<U> &) { return true;  }
    template <class T, class U> bool operator!=(const SimpleAllocator<T> &, const SimpleAllocator<U> &) { return false; }
}

namespace shared {

    template <typename T> using allocator = SimpleAllocator<T>;
    template<typename T>  using set       = std::set<T, std::less<T>, allocator<T> >;

    template <typename Domain, typename Codomain>
    using basic_map = icl::interval_map<Domain, Codomain,
            icl::partial_absorber, std::less, icl::inplace_plus, icl::inter_section, icl::discrete_interval<int, std::less>,
            allocator
        >;

    using map      = basic_map<int, set<int> >;
    using interval = map::interval_type;
}

#include <iostream>

int main() {

    shared::map demo;
    for (auto&& element : {
            shared::map::value_type { shared::interval::right_open(4, 5), { 1, 7, } },
            shared::map::value_type { shared::interval::right_open(2, 6), { 1, 2, 3, } },
        })
    {
        demo.add(element);
        std::cout << "adding: " << element.first << ", result: " << demo << "\n";
    }
}

I used managed_mapped_file instead of maneged_shared_memory because the latter is not support on the online compiler.


¹ or using a "type function" in c++03

sehe
  • 374,641
  • 47
  • 450
  • 633
  • I'm currently [still trying to make that work](https://www.livecoding.tv/sehe/) but I'm having trouble satisfying/understanding all the [allocator requirements](http://en.cppreference.com/w/cpp/concept/Allocator) again. Will post more later – sehe Jul 08 '15 at 08:53
  • I found my silly mistake in the implementation. Added a **[Live Sample](http://coliru.stacked-crooked.com/a/58539e4352339523)** which uses a global shared memory segment for allocations. I think it's hacky but it might be good enough for your application. – sehe Jul 08 '15 at 09:09
  • Thanks it works :) Now i have to make sense of it :) – Asna Jul 08 '15 at 10:42
  • @user3559050 Yeah. If you want, you can see the **[vod I was live-streaming at the time](https://www.livecoding.tv/video/putting-boost-icl-containers-in-shared-memory/)** ² I have some thoughts about making this workaround... "palatable" in case you need/want to use it. (² note how I lose about 30 minutes because I can't get the arguments to `std::set<>` right...) – sehe Jul 08 '15 at 17:49
  • your input was very valuable! But I tested my code by creating another process and accessing the same map since it is in file/ shared memory but I got it empty in other process ? – Asna Aug 19 '15 at 13:09
  • Seems like it's time to post a new question then. Please provide a SSCCE and details about your runtime environment – sehe Aug 19 '15 at 13:24
  • there you go http://stackoverflow.com/questions/32097385/boost-icl-shared-memory-access – Asna Aug 19 '15 at 13:50