Main Page · Modules · All Classes · Class Hierarchy
MASignal.hpp
1 /*Copyright (c) 2007 by Ben Sunshine-Hill
2 
3 Permission is hereby granted, free of charge, to any person or organization
4 obtaining a copy of the software and accompanying documentation covered by
5 this license (the "Software") to use, reproduce, display, distribute,
6 execute, and transmit the Software, and to prepare derivative works of the
7 Software, and to permit third-parties to whom the Software is furnished to
8 do so, all subject to the following:
9 
10 The copyright notices in the Software and this entire statement, including
11 the above license grant, this restriction and the following disclaimer,
12 must be included in all copies of the Software, in whole or in part, and
13 all derivative works of the Software, unless such copies or derivative
14 works are solely in the form of machine-executable object code generated by
15 a source language processor.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE.*/
24 
25 #pragma once
26 
27 #define MA_SLOT_CLASS \
28  protected: \
29  MAConnectionSet SignalConnections; \
30  public:
31 
32 #define MA_SIGNAL_CONNECT(_signal, _slot) \
33  SignalConnections.Add(_signal->Register(*this, &_slot));
34 
35 #define MAX_SIGNAL_ARGS 4
36 
37 #include "3rdparty/FastDelegate.h"
38 
39 #include <boost/noncopyable.hpp>
40 #include <boost/preprocessor/iteration.hpp>
41 #include <boost/preprocessor/repetition.hpp>
42 #include <boost/preprocessor/cat.hpp>
43 #include <boost/preprocessor/if.hpp>
44 #include <boost/preprocessor/comparison.hpp>
45 #include <boost/preprocessor/empty.hpp>
46 #include <boost/preprocessor/arithmetic.hpp>
47 #include <boost/preprocessor/logical.hpp>
48 #include <boost/preprocessor/comma_if.hpp>
49 
50 #include <vector>
51 #include <utility>
52 
53 template<typename T>
54 struct MASignalNode
55 {
56  MASignalNode(T const& data, MASignalNode<T>* next) : next(next), refCount(0), data(data) { }
57  MASignalNode<T>* next;
58  // refCount is as follows:
59  // n>0: Connection is still active, thanks to n holders
60  // n<0: Event has been destroyed, but -n holders are left
61  // n=0: Connection has been closed, but Event still exists
62  int refCount;
63  T data;
64 };
65 
66 class MASignalNullType{};
67 
68 class MAConnection
69 {
70 public:
71  MAConnection() : m_node(0) { }
72  template<typename DelegateType>
73  explicit MAConnection(MASignalNode<DelegateType>* m_node) :
74  m_node(reinterpret_cast<AnyNodeType*>(m_node))
75  {
76  if(m_node)
77  {
78  m_node->refCount++;
79  }
80  }
81 
82  MAConnection(MAConnection const& c) : m_node(c.m_node && c.m_node->refCount > 0 ? c.m_node : 0)
83  {
84  if(m_node)
85  {
86  m_node->refCount++;
87  }
88  }
89 
90  MAConnection& operator=(MAConnection const& c)
91  {
92  if(&c == this) return *this;
93 
94  if(m_node)
95  {
96  if(m_node->refCount > 0)
97  {
98  m_node->refCount--;
99  }
100  else if(m_node->refCount < 0)
101  {
102  m_node->refCount++;
103  if(m_node->refCount == 0)
104  {
105  delete m_node;
106  }
107  }
108  }
109 
110  m_node = c.m_node && c.m_node->refCount > 0 ? c.m_node : 0;
111  if(m_node)
112  {
113  m_node->refCount++;
114  }
115 
116  return *this;
117  }
118 
119  ~MAConnection()
120  {
121  if(m_node)
122  {
123  if(m_node->refCount > 0)
124  {
125  m_node->refCount--;
126  }
127  else if(m_node->refCount < 0)
128  {
129  m_node->refCount++;
130  if(m_node->refCount == 0)
131  {
132  delete m_node;
133  }
134  }
135  }
136  }
137 
138  bool Active() const
139  {
140  return m_node != nullptr && m_node->refCount > 0;
141  }
142 
143  typedef MASignalNode<MASignalNullType> AnyNodeType;
144  AnyNodeType* m_node;
145 };
146 
147 class MAConnectionSet
148 {
149 public:
150  void Add(MAConnection const& c)
151  {
152  m_connections.push_back(c);
153  }
154 
155  void Clear()
156  {
157  m_connections.clear();
158  }
159 
160 private:
161  typedef std::vector<MAConnection> ConnectionContainer;
162  ConnectionContainer m_connections;
163 };
164 
165 template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(MAX_SIGNAL_ARGS, typename T, MASignalNullType)>
166 class MASignal;
167 
168 class AutoTracked : private MAConnectionSet
169 {
170 private:
171  template<BOOST_PP_ENUM_PARAMS(MAX_SIGNAL_ARGS, typename T)>
172  friend class MASignal;
173 };
174 
175 
176 #define BOOST_PP_ITERATION_LIMITS (0, BOOST_PP_SUB(MAX_SIGNAL_ARGS,1))
177 #define BOOST_PP_FILENAME_1 "core/MASignalImpl.hpp"
178 #include BOOST_PP_ITERATE()
179 #undef BOOST_PP_ITERATION_LIMITS
180 #undef BOOST_PP_FILENAME_1
181 #undef nullptrTYPE_MACRO
182 
183 namespace std
184 {
185  template<>
186  inline void swap<MAConnection>(MAConnection & left, MAConnection & right)
187  {
188  std::swap(left.m_node, right.m_node);
189  }
190 }