Orocos Real-Time Toolkit
2.6.0
|
00001 /*************************************************************************** 00002 tag: Peter Soetens Thu Oct 22 11:59:08 CEST 2009 ReadOnlyPointer.hpp 00003 00004 ReadOnlyPointer.hpp - description 00005 ------------------- 00006 begin : Thu October 22 2009 00007 copyright : (C) 2009 Sylvain Joyeux 00008 email : Sylvain Joyeux <sylvain.joyeux@m4x.org> 00009 00010 *************************************************************************** 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of the GNU General Public * 00013 * License as published by the Free Software Foundation; * 00014 * version 2 of the License. * 00015 * * 00016 * As a special exception, you may use this file as part of a free * 00017 * software library without restriction. Specifically, if other files * 00018 * instantiate templates or use macros or inline functions from this * 00019 * file, or you compile this file and link it with other files to * 00020 * produce an executable, this file does not by itself cause the * 00021 * resulting executable to be covered by the GNU General Public * 00022 * License. This exception does not however invalidate any other * 00023 * reasons why the executable file might be covered by the GNU General * 00024 * Public License. * 00025 * * 00026 * This library is distributed in the hope that it will be useful, * 00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00029 * Lesser General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public * 00032 * License along with this library; if not, write to the Free Software * 00033 * Foundation, Inc., 59 Temple Place, * 00034 * Suite 330, Boston, MA 02111-1307 USA * 00035 * * 00036 ***************************************************************************/ 00037 00038 00039 #ifndef RTT_READ_WRITE_POINTER_HPP 00040 #define RTT_READ_WRITE_POINTER_HPP 00041 00042 #include <boost/intrusive_ptr.hpp> 00043 #include <boost/call_traits.hpp> 00044 00045 #include "../os/Mutex.hpp" 00046 #include "../os/MutexLock.hpp" 00047 00048 namespace RTT 00049 { namespace extras { 00050 00051 template<typename T> 00052 struct ROPtrInternal 00053 { 00054 os::Mutex lock; 00055 T* value; 00056 size_t readers; 00057 00058 ROPtrInternal(T* value) 00059 : value(value), readers(0) {} 00060 ~ROPtrInternal() { delete value; } 00061 00062 void ref() 00063 { os::MutexLock do_lock(lock); 00064 ++readers; 00065 } 00066 bool deref() 00067 { os::MutexLock do_lock(lock); 00068 return (--readers) != 0; 00069 } 00070 }; 00071 00072 template<typename T> 00073 void intrusive_ptr_add_ref(ROPtrInternal<T>* data) 00074 { 00075 data->ref(); 00076 } 00077 template<typename T> 00078 void intrusive_ptr_release(ROPtrInternal<T>* data) 00079 { 00080 if (!data->deref()) 00081 delete data; 00082 } 00083 00097 template<typename T> 00098 class ReadOnlyPointer 00099 { 00100 typedef ROPtrInternal<T> Internal; 00101 boost::intrusive_ptr<Internal> internal; 00102 typedef boost::call_traits<T> traits; 00103 00104 public: 00105 ReadOnlyPointer(T* ptr = 0) 00106 : internal(new Internal(ptr)) {} 00107 00108 typename traits::const_reference operator *() const { return *(internal->value); } 00109 T const* operator ->() const { return internal->value; } 00110 00112 bool valid() const 00113 { return internal->value != 0; } 00114 00115 T const* get() const 00116 { 00117 return internal->value; 00118 } 00119 00141 void reset(T* ptr) 00142 { 00143 boost::intrusive_ptr<Internal> safe = this->internal; 00144 if (!safe) 00145 { 00146 internal = new Internal(ptr); 00147 return; 00148 } 00149 00150 00151 { os::MutexLock do_lock(safe->lock); 00152 if (safe->readers == 2) // we are sole owner 00153 { 00154 delete safe->value; 00155 safe->value = ptr; 00156 return; 00157 } 00158 } 00159 00160 // We must *not* change 'internal' while safe->lock is taken. The 00161 // above block returns in case we don't need to reallocate a new 00162 // Internal structure. 00163 // 00164 // In other words, if we are here, it is because we *need* to 00165 // reallocate. 00166 internal = new Internal(ptr); 00167 } 00168 00178 T* try_write_access() 00179 { 00180 boost::intrusive_ptr<Internal> safe = this->internal; 00181 if (!safe) 00182 return 0; 00183 00184 { os::MutexLock do_lock(safe->lock); 00185 if (safe->readers == 2) 00186 { // we're the only owner (don't forget +safe+ above). 00187 // Just promote the current copy 00188 T* value = 0; 00189 std::swap(value, safe->value); 00190 return value; 00191 } 00192 else 00193 { // there are other owners 00194 return NULL; 00195 } 00196 } 00197 } 00198 00210 T* write_access() 00211 { 00212 boost::intrusive_ptr<Internal> safe = this->internal; 00213 if (!safe) 00214 return 0; 00215 00216 { os::MutexLock do_lock(safe->lock); 00217 if (safe->readers == 2) 00218 { // we're the only owner (don't forget +safe+ above). 00219 // Just promote the current copy 00220 T* value = 0; 00221 std::swap(value, safe->value); 00222 return value; 00223 } 00224 else 00225 { // there are other owners, do a copy 00226 return new T(*safe->value); 00227 } 00228 } 00229 } 00230 }; 00231 }} 00232 00233 #endif 00234