Using mutexes around accesses to refcounts seems to make the Windows build much less...
[synfig.git] / synfig-core / trunk / src / synfig / node.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file node.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007, 2008 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include "node.h"
34 #include "nodebase.h"
35
36 #ifdef HASH_MAP_H
37 #include HASH_MAP_H
38 #else
39 #include <map>
40 #endif
41
42 #endif
43
44 /* === U S I N G =========================================================== */
45
46 using namespace std;
47 using namespace etl;
48 using namespace synfig;
49
50 /* === M A C R O S ========================================================= */
51
52 // About BE_FRUGAL_WITH_GUIDS
53 // If this macro is set, then a GUID will NOT
54 // be calculated until the first call to get_guid()
55 // This also means that the node doesn't get
56 // added to the database until get_guid() is called
57 // for the first time, or set_guid() is called.
58 // If it is expensive to calculate GUIDs, then
59 // this can improve performance a tad in
60 // some cases. Otherwise, it doesn't change
61 // much of anything.
62 #define BE_FRUGAL_WITH_GUIDS 1
63
64 #ifndef __sys_clock
65 #ifndef _WIN32
66 # include <time.h>
67 # define __sys_clock    ::clock
68 #else
69 # ifdef __GNUG__
70 #  include <time.h>
71 #  define __sys_clock   ::clock
72 # else
73 typedef int clock_t;
74 extern clock_t _clock();
75 #  define CLOCKS_PER_SEC 1000
76 #  define __sys_clock   _clock
77 # endif
78 #endif
79 #endif
80
81 /* === G L O B A L S ======================================================= */
82
83 #ifdef HASH_MAP_H
84 typedef HASH_MAP_CLASS<synfig::GUID,Node*,GUIDHash> GlobalNodeMap;
85 #else
86 typedef map<synfig::GUID,Node*> GlobalNodeMap;
87 #endif
88
89 static GlobalNodeMap* global_node_map_;
90
91 static GlobalNodeMap& global_node_map()
92 {
93         if(!global_node_map_)
94                 global_node_map_=new GlobalNodeMap;
95         return *global_node_map_;
96 }
97
98 /* === P R O C E D U R E S ================================================= */
99
100 synfig::Node*
101 synfig::find_node(const synfig::GUID& guid)
102 {
103         if(global_node_map().count(guid)==0)
104                 return 0;
105         return global_node_map()[guid];
106 }
107
108 static void
109 refresh_node(synfig::Node* node, synfig::GUID old_guid)
110 {
111         assert(global_node_map().count(old_guid));
112         global_node_map().erase(old_guid);
113         assert(!global_node_map().count(old_guid));
114         global_node_map()[node->get_guid()]=node;
115 }
116
117 /* === M E T H O D S ======================================================= */
118
119 #ifdef _DEBUG
120 const char *
121 TimePoint::c_str()const
122 {
123         return get_time().get_string().c_str();
124 }
125 #endif
126
127 void
128 TimePoint::absorb(const TimePoint& x)
129 {
130         if(get_guid()==x.get_guid())
131                 return;
132         set_guid(get_guid()^x.get_guid());
133
134         if(get_after()==INTERPOLATION_NIL)
135                 set_after(x.get_after());
136         if(get_before()==INTERPOLATION_NIL)
137                 set_before(x.get_before());
138
139         if(get_after()!=x.get_after() && x.get_after()!=INTERPOLATION_NIL)
140                 set_after(INTERPOLATION_UNDEFINED);
141         if(get_before()!=x.get_before() && x.get_before()!=INTERPOLATION_NIL)
142                 set_before(INTERPOLATION_UNDEFINED);
143 }
144
145 TimePointSet::iterator
146 TimePointSet::insert(const TimePoint& x)
147 {
148         iterator iter(find(x));
149         if(iter!=end())
150         {
151                 const_cast<TimePoint&>(*iter).absorb(x);
152                 return iter;
153         }
154         return std::set<TimePoint>::insert(x).first;
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 Node::Node():
172         guid_(0),
173         bchanged(true),
174         time_last_changed_(__sys_clock()),
175         deleting_(false)
176 {
177 #ifndef BE_FRUGAL_WITH_GUIDS
178         guid_.make_unique();
179         assert(guid_);
180         assert(!global_node_map().count(guid_));
181         global_node_map()[guid_]=this;
182 #endif
183 }
184
185 Node::~Node()
186 {
187         begin_delete();
188
189         if(guid_)
190         {
191                 assert(global_node_map().count(guid_));
192                 global_node_map().erase(guid_);
193                 assert(!global_node_map().count(guid_));
194         }
195 }
196
197 void
198 Node::changed()
199 {
200         time_last_changed_=__sys_clock();
201         on_changed();
202 }
203
204
205 //! Gets the GUID for this value node
206 const synfig::GUID&
207 Node::get_guid()const
208 {
209 #ifdef BE_FRUGAL_WITH_GUIDS
210         if(!guid_)
211         {
212                 const_cast<synfig::GUID&>(guid_).make_unique();
213                 assert(guid_);
214                 assert(!global_node_map().count(guid_));
215                 global_node_map()[guid_]=const_cast<Node*>(this);
216         }
217 #endif
218
219         return guid_;
220 }
221
222 //! Sets the GUID for this value node
223 void
224 Node::set_guid(const synfig::GUID& x)
225 {
226         assert(x);
227
228 #ifdef BE_FRUGAL_WITH_GUIDS
229         if(!guid_)
230         {
231                 guid_=x;
232                 assert(!global_node_map().count(guid_));
233                 global_node_map()[guid_]=this;
234         }
235         else
236 #endif
237         if(guid_!=x)
238         {
239                 synfig::GUID oldguid(guid_);
240                 guid_=x;
241                 refresh_node(this, oldguid);
242                 on_guid_changed(oldguid);
243         }
244 }
245
246 int
247 Node::get_time_last_changed()const
248 {
249         return time_last_changed_;
250 }
251
252 void
253 Node::add_child(Node*x)
254 {
255         x->parent_set.insert(this);
256 }
257
258 void
259 Node::remove_child(Node*x)
260 {
261         if(x->parent_set.count(this)) x->parent_set.erase(this);
262 }
263
264 int
265 Node::parent_count()const
266 {
267         return parent_set.size();
268 }
269
270 const Node::time_set &
271 Node::get_times() const
272 {
273         if(bchanged)
274         {
275                 times.clear();
276                 get_times_vfunc(times);
277                 bchanged = false;
278         }
279
280         //set the output set...
281         return times;
282 }
283
284 void
285 Node::begin_delete()
286 {
287         if(!deleting_)
288         {
289                 deleting_=true; signal_deleted()();
290         }
291 }
292
293 void
294 Node::on_changed()
295 {
296         bchanged = true;
297         signal_changed()();
298
299         std::set<Node*>::iterator iter;
300         for(iter=parent_set.begin();iter!=parent_set.end();++iter)
301         {
302                 (*iter)->changed();
303         }
304 }
305
306 void
307 Node::on_guid_changed(synfig::GUID guid)
308 {
309         signal_guid_changed()(guid);
310 }