summaryrefslogtreecommitdiff
path: root/core/multi_queue.hpp
blob: b77785b9c8c358c3d1bcf30002e41450d51506d5 (plain)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#ifndef JszL9wNT11XcdnV6wZR3NcSJB0
#define JszL9wNT11XcdnV6wZR3NcSJB0

#include <assert.h>

#include <boost/mpl/list.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/front.hpp>
#include <boost/mpl/empty.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/pop_front.hpp>
#include <boost/mpl/back.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/tuple/tuple.hpp>

#include "heap.hpp"
#include "priority_queue.hpp"
#include "quant_types.hpp"
#include "template_helpers.hpp"
#include "type_set.hpp"

namespace MultiQueueImpl {

  using namespace boost;
  using namespace boost::mpl;
  using boost::mpl::empty;
  using boost::mpl::size;
  
  const unsigned char numRID =
    1 + RuntimeID<back<DiscreteQuantorList>::type>::value;

  template<typename Val, typename Payload>
  struct DefaultContainer {
    typedef Heap<PriorityQueue<Val, Payload>> type;
  };

  // the actual class (the only one lifted)
  template <typename Val, // keys to be sorted
	    template<typename X> class Payload, // values belongig to above keys
	    typename Members, // list of all data sources
	    template<typename _Val, typename _Payload> class Container
	    = DefaultContainer> // queue impl
  struct MultiQueue {
    // type constructions
    typedef typename size<Members>::type numMembers;
    typedef typename transform<Members, 
			       Container<Val, Payload<_>>
			       >::type MemberList;
    //    typedef typename CalcSetType<Val, Container, Payload, Members>::type MemberList;
    typedef typename UnpackTypeList<TypeSet, MemberList>::type set_t;

    // get time and type of min element
    Val min() {
      return minVal[1];
    }

    uint8_t minType() {
      return minRID[1];
    }

    // insert event
    template<typename Quant>
    inline void insert(Val ct, Val val, Payload<Quant> payload) {
      assert(ct() <= val());
      BOOST_STATIC_ASSERT(( numRID > RuntimeID<Quant>::value ));
      get<Quant>()(ct).insert(val, payload);

      uint pos = RIDpos[RuntimeID<Quant>::value];
      minVal[pos] = get<Quant>()(ct).minVal();
    
      // correct order; val can only decrease -> bubble down
      for (uint i=pos-1; maybeSwap(i); i--);
    }  

    // remove min event; ugly part: caller has to supply correct quant
    // and position
    template<typename Quant>
    inline void removeMin(Val ct, uint pos=1) {
      assert(RuntimeID<Quant>::value == minRID[pos]);

      get<Quant>()(ct).removeMin();
      minVal[pos] = get<Quant>()(ct).isEmpty() 
	? Val::never() 
	: get<Quant>()(ct).minVal();
    
      // correct order; val can only increase -> bubble up
      for (int i=pos; maybeSwap(i); i++);
    }

    // like removeMin, but the quant does not need to be the current
    // global min and no position has to be specified
    template<typename Quant>
    inline void removeLocalMin(Val ct) {
      removeMin<Quant>(ct, RIDpos[RuntimeID<Quant>::value]);
    }

    // constructor
    template<typename... Arg>
    MultiQueue(Arg... arg) : typeSet(std::move(arg)...) {
      init();
    }

    MultiQueue() : typeSet() {
      init();
    }

    void init() {
      // set fake entries (to avoid boundary condition during sorting)
      minVal[0] = Val::beforeAll();
      minRID[0] = -1;
      // (and prefill minVal/minRID in case of missing values in loadInitial())
      for (int i=1; i<=numMembers::value + 1; i++) {
	minVal[i] = Val::never();
	minRID[i] = i - 1;
      }

      // init queue head caches
      loadInitial<Members>();

      // blind in-place bubble sort
      for (int i=0; i<numMembers::value; i++)
	for (int j=1; j<numMembers::value; j++)
	  maybeSwap(j);
    }

    template<typename RemMembers>
    void loadInitial(uint pos=1) {
      typedef typename front<RemMembers>::type head_t;
      typedef empty<typename pop_front<RemMembers>::type> isLast_t;
      typedef typename if_<isLast_t,
			   RemMembers,
			   typename pop_front<RemMembers>::type
			   >::type tail_t;

      // read current time from heaps
      Val ct = get<head_t>().currentTime;

      // init queue head caches
      minRID[pos] = RuntimeID<head_t>::value;
      if (get<head_t>()(ct).isEmpty()) {
	minVal[pos] = Val::never();
      }else{
	minVal[pos] = get<head_t>()(ct).minVal();
      }
      RIDpos[RuntimeID<head_t>::value] = pos;
  
      // template recursion
      if (!is_same<RemMembers, tail_t>::value)
      	loadInitial<tail_t>(pos+1);
    }

    // access underlying queues directly
    template <typename Quant>
    inline typename Container<Val, Payload<Quant>>::type & get() {
	return typeSet.get<typename Container<Val, Payload<Quant>>::type>();
    }
    
    // swap if i and i+1 are in wrong order; return if swapped
    inline bool maybeSwap(uint i) {
      // check if order is violated
      if (minVal[i] <  minVal[i+1]) return false;
      if ((minVal[i] == minVal[i+1]) && (minRID[i] <= minRID[i+1])) return false; // sort by RID if val is equal

      // swap
      std::swap(minVal[i], minVal[i+1]);
      std::swap(minRID[i], minRID[i+1]);
      RIDpos[minRID[i]] = i;
      RIDpos[minRID[i + 1]] = i + 1;
      return true;
    }

    // data
    set_t typeSet;
    
    Val minVal[numMembers::value + 2];
    uint minRID[numMembers::value + 2];
    uint RIDpos[numRID];
  };
}

using MultiQueueImpl::MultiQueue;

#endif // JszL9wNT11XcdnV6wZR3NcSJB0
contact: Jan Huwald // Impressum