]> git.tdb.fi Git - ext/sigc++-2.0.git/blob - sigc++/trackable.cc
Adjust the name of the library to match upstream
[ext/sigc++-2.0.git] / sigc++ / trackable.cc
1 /*
2  * Copyright 2002, The libsigc++ Development Team
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  */
19
20 #include <sigc++/trackable.h>
21
22 namespace sigc
23 {
24
25 trackable::trackable() noexcept
26 : callback_list_(nullptr)
27 {}
28
29 /* Don't copy the notification list.
30    The objects watching src don't need to be notified when the new object dies. */
31 trackable::trackable(const trackable& /*src*/) noexcept
32 : callback_list_(nullptr)
33 {}
34
35 // Don't move the notification list.
36 // The objects watching src don't need to be notified when the new object dies.
37 // They need to be notified now, because src probably becomes useless.
38 //
39 // If trackable's move constructor is modified, check if Glib::Object's
40 // move constructor should be modified similarly.
41 trackable::trackable(trackable&& src)
42 : callback_list_(nullptr)
43 {
44   src.notify_callbacks();
45 }
46
47 trackable& trackable::operator=(const trackable& src)
48 {
49   if(this != &src)
50     notify_callbacks(); //Make sure that we have finished with existing stuff before replacing it.
51   
52   return *this;
53 }
54
55 trackable& trackable::operator=(trackable&& src)
56 {
57   if(this != &src)
58   {
59     notify_callbacks(); //Make sure that we have finished with existing stuff before replacing it.
60     src.notify_callbacks(); // src probably becomes useless.
61   }
62   return *this;
63 }
64
65 trackable::~trackable()
66 {
67   notify_callbacks();
68 }
69
70 void trackable::add_destroy_notify_callback(void* data, func_destroy_notify func) const
71 {
72   callback_list()->add_callback(data, func);
73 }
74
75 void trackable::remove_destroy_notify_callback(void* data) const
76 {
77   callback_list()->remove_callback(data);
78 }
79
80 void trackable::notify_callbacks()
81 {
82   if (callback_list_)
83     delete callback_list_; //This invokes all of the callbacks.
84
85   callback_list_ = nullptr;
86 }
87
88 internal::trackable_callback_list* trackable::callback_list() const
89 {
90   if (!callback_list_)
91     callback_list_ = new internal::trackable_callback_list;
92
93   return callback_list_;
94 }
95
96       
97 namespace internal
98 {
99
100 trackable_callback_list::~trackable_callback_list()
101 {
102   clearing_ = true;
103
104   for (auto& callback : callbacks_)
105     if (callback.func_)
106       callback.func_(callback.data_);
107 }
108
109 void trackable_callback_list::add_callback(void* data, func_destroy_notify func)
110 {
111   if (!clearing_)  // TODO: Is it okay to silently ignore attempts to add dependencies when the list is being cleared?
112                    //       I'd consider this a serious application bug, since the app is likely to segfault.
113                    //       But then, how should we handle it? Throw an exception? Martin.
114     callbacks_.push_back(trackable_callback(data, func));
115 }
116
117 void trackable_callback_list::clear()
118 {
119   clearing_ = true;
120
121   for (auto& callback : callbacks_)
122     if (callback.func_) 
123       callback.func_(callback.data_);
124
125   callbacks_.clear();
126
127   clearing_ = false;
128 }
129
130 void trackable_callback_list::remove_callback(void* data)
131 {
132   for (callback_list::iterator i = callbacks_.begin(); i != callbacks_.end(); ++i)
133   {
134     auto& callback = *i;
135     if (callback.data_ == data && callback.func_ != nullptr)
136     {
137       //Don't remove a list element while the list is being cleared.
138       //It could invalidate the iterator in ~trackable_callback_list() or clear().
139       //But it may be necessary to invalidate the callback. See bug 589202.
140       if (clearing_)
141         callback.func_ = nullptr;
142       else
143         callbacks_.erase(i);
144       return;
145     }
146   }
147 }
148
149 } /* namespace internal */
150
151 } /* namespace sigc */