summaryrefslogtreecommitdiffstats
blob: 5e1853a51821332cc14cfdccbb6b6ec93003e088 (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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
// Boost.Signals2 library

// Copyright Frank Mori Hess 2007-2008.
// Use, modification and
// distribution is subject to the Boost Software License, Version
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// For more information, see http://www.boost.org

#ifndef BOOST_SIGNALS2_SLOT_GROUPS_HPP
#define BOOST_SIGNALS2_SLOT_GROUPS_HPP

#include <boost/signals2/connection.hpp>
#include <boost/optional.hpp>
#include <list>
#include <map>
#include <utility>

namespace boost {
  namespace signals2 {
    namespace detail {
      enum slot_meta_group {front_ungrouped_slots, grouped_slots, back_ungrouped_slots};
      template<typename Group>
      struct group_key
      {
        typedef std::pair<enum slot_meta_group, boost::optional<Group> > type;
      };
      template<typename Group, typename GroupCompare>
      class group_key_less
      {
      public:
        group_key_less()
        {}
        group_key_less(const GroupCompare &group_compare): _group_compare(group_compare)
        {}
        bool operator ()(const typename group_key<Group>::type &key1, const typename group_key<Group>::type &key2) const
        {
          if(key1.first != key2.first) return key1.first < key2.first;
          if(key1.first != grouped_slots) return false;
          return _group_compare(key1.second.get(), key2.second.get());
        }
      private:
        GroupCompare _group_compare;
      };
      template<typename Group, typename GroupCompare, typename ValueType>
      class grouped_list
      {
      public:
        typedef group_key_less<Group, GroupCompare> group_key_compare_type;
      private:
        typedef std::list<ValueType> list_type;
        typedef std::map
          <
            typename group_key<Group>::type,
            typename list_type::iterator,
            group_key_compare_type
          > map_type;
        typedef typename map_type::iterator map_iterator;
        typedef typename map_type::const_iterator const_map_iterator;
      public:
        typedef typename list_type::iterator iterator;
        typedef typename list_type::const_iterator const_iterator;
        typedef typename group_key<Group>::type group_key_type;

        grouped_list(const group_key_compare_type &group_key_compare):
          _group_key_compare(group_key_compare)
        {}
        grouped_list(const grouped_list &other): _list(other._list),
          _group_map(other._group_map), _group_key_compare(other._group_key_compare)
        {
          // fix up _group_map
          typename map_type::const_iterator other_map_it;
          typename list_type::iterator this_list_it = _list.begin();
          typename map_type::iterator this_map_it = _group_map.begin();
          for(other_map_it = other._group_map.begin();
            other_map_it != other._group_map.end();
            ++other_map_it, ++this_map_it)
          {
            BOOST_ASSERT(this_map_it != _group_map.end());
            this_map_it->second = this_list_it;
            typename list_type::const_iterator other_list_it = other.get_list_iterator(other_map_it);
            typename map_type::const_iterator other_next_map_it = other_map_it;
            ++other_next_map_it;
            typename list_type::const_iterator other_next_list_it = other.get_list_iterator(other_next_map_it);
            while(other_list_it != other_next_list_it)
            {
              ++other_list_it;
              ++this_list_it;
            }
          }
        }
        iterator begin()
        {
          return _list.begin();
        }
        iterator end()
        {
          return _list.end();
        }
        iterator lower_bound(const group_key_type &key)
        {
          map_iterator map_it = _group_map.lower_bound(key);
          return get_list_iterator(map_it);
        }
        iterator upper_bound(const group_key_type &key)
        {
          map_iterator map_it = _group_map.upper_bound(key);
          return get_list_iterator(map_it);
        }
        void push_front(const group_key_type &key, const ValueType &value)
        {
          map_iterator map_it;
          if(key.first == front_ungrouped_slots)
          {// optimization
            map_it = _group_map.begin();
          }else
          {
            map_it = _group_map.lower_bound(key);
          }
          m_insert(map_it, key, value);
        }
        void push_back(const group_key_type &key, const ValueType &value)
        {
          map_iterator map_it;
          if(key.first == back_ungrouped_slots)
          {// optimization
            map_it = _group_map.end();
          }else
          {
            map_it = _group_map.upper_bound(key);
          }
          m_insert(map_it, key, value);
        }
        void erase(const group_key_type &key)
        {
          map_iterator map_it = _group_map.lower_bound(key);
          iterator begin_list_it = get_list_iterator(map_it);
          iterator end_list_it = upper_bound(key);
          if(begin_list_it != end_list_it)
          {
            _list.erase(begin_list_it, end_list_it);
            _group_map.erase(map_it);
          }
        }
        iterator erase(const group_key_type &key, const iterator &it)
        {
          BOOST_ASSERT(it != _list.end());
          map_iterator map_it = _group_map.lower_bound(key);
          BOOST_ASSERT(map_it != _group_map.end());
          BOOST_ASSERT(weakly_equivalent(map_it->first, key));
          if(map_it->second == it)
          {
            iterator next = it;
            ++next;
            // if next is in same group
            if(next != upper_bound(key))
            {
              _group_map[key] = next;
            }else
            {
              _group_map.erase(map_it);
            }
          }
          return _list.erase(it);
        }
        void clear()
        {
          _list.clear();
          _group_map.clear();
        }
      private:
        /* Suppress default assignment operator, since it has the wrong semantics. */
        grouped_list& operator=(const grouped_list &other);

        bool weakly_equivalent(const group_key_type &arg1, const group_key_type &arg2)
        {
          if(_group_key_compare(arg1, arg2)) return false;
          if(_group_key_compare(arg2, arg1)) return false;
          return true;
        }
        void m_insert(const map_iterator &map_it, const group_key_type &key, const ValueType &value)
        {
          iterator list_it = get_list_iterator(map_it);
          iterator new_it = _list.insert(list_it, value);
          if(map_it != _group_map.end() && weakly_equivalent(key, map_it->first))
          {
            _group_map.erase(map_it);
          }
          map_iterator lower_bound_it = _group_map.lower_bound(key);
          if(lower_bound_it == _group_map.end() ||
            weakly_equivalent(lower_bound_it->first, key) == false)
          {
            /* doing the following instead of just
              _group_map[key] = new_it;
              to avoid bogus error when enabling checked iterators with g++ */
            _group_map.insert(typename map_type::value_type(key, new_it));
          }
        }
        iterator get_list_iterator(const const_map_iterator &map_it)
        {
          iterator list_it;
          if(map_it == _group_map.end())
          {
            list_it = _list.end();
          }else
          {
            list_it = map_it->second;
          }
          return list_it;
        }
        const_iterator get_list_iterator(const const_map_iterator &map_it) const
        {
          const_iterator list_it;
          if(map_it == _group_map.end())
          {
            list_it = _list.end();
          }else
          {
            list_it = map_it->second;
          }
          return list_it;
        }

        list_type _list;
        // holds iterators to first list item in each group
        map_type _group_map;
        group_key_compare_type _group_key_compare;
      };
    } // end namespace detail
    enum connect_position { at_back, at_front };
  } // end namespace signals2
} // end namespace boost

#endif // BOOST_SIGNALS2_SLOT_GROUPS_HPP