blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Quest Software, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Quest Software, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00039 #ifndef BLOCXX_LAZY_GLOBAL_HPP_INCLUDE_GUARD_ 00040 #define BLOCXX_LAZY_GLOBAL_HPP_INCLUDE_GUARD_ 00041 00042 #include "blocxx/BLOCXX_config.h" 00043 #include "blocxx/ThreadOnce.hpp" 00044 #include "blocxx/GlobalPtr.hpp" 00045 00046 #ifdef BLOCXX_HAVE_STD_TR1_IS_POD 00047 #include "blocxx/StaticAssert.hpp" 00048 00049 #include <tr1/type_traits> 00050 #endif 00051 00052 namespace BLOCXX_NAMESPACE 00053 { 00054 00055 template <typename T, typename PODType> 00056 struct DefaultVariableConstructorFactory 00057 { 00058 static T* create(const PODType& t) 00059 { 00060 return new T(t); 00061 } 00062 }; 00063 00113 template <typename T, typename PODType, typename FactoryT = DefaultVariableConstructorFactory<T, PODType> > 00114 class LazyGlobal 00115 { 00116 #ifdef BLOCXX_HAVE_STD_TR1_IS_POD 00117 BLOCXX_STATIC_ASSERT(std::tr1::is_pod<PODType>::value); 00118 #endif 00119 private: 00120 struct InitPtr 00121 { 00122 InitPtr(T*& p, const PODType& str) 00123 : m_p(p) 00124 , m_pod(str) 00125 { } 00126 T*& m_p; 00127 const PODType& m_pod; 00128 00129 void operator()() 00130 { 00131 m_p = static_cast<T*>(FactoryT::create(m_pod)); 00132 } 00133 }; 00134 00135 T* getPtr() const 00136 { 00137 callOnce(m_onceFlag, InitPtr(m_p, m_pod)); 00138 return m_p; 00139 } 00140 00141 public: 00142 ~LazyGlobal() 00143 { 00144 delete m_p; 00145 // reset these variables in case get() is called after the destructor runs. 00146 m_p = 0; 00147 OnceFlag tmp = BLOCXX_ONCE_INIT; 00148 m_onceFlag = tmp; 00149 } 00150 00151 T& get() const 00152 { 00153 callOnce(m_onceFlag, InitPtr(m_p, m_pod)); 00154 return *m_p; 00155 } 00156 00157 // The two different operators are defined because there may be some 00158 // global variables marked as const. We'll want them treated 00159 // differently. 00160 operator T&() 00161 { 00162 return get(); 00163 } 00164 00165 operator const T&() const 00166 { 00167 return get(); 00168 } 00169 00170 template<typename T2> 00171 T& operator=(const T2& rhs) 00172 { 00173 // checking for self assignment is handled by type T 00174 return (get() = rhs); 00175 } 00176 00177 // These members should be treated as private. They aren't marked private 00178 // because if they are, POD initializer syntax can't be used. 00179 PODType m_pod; 00180 mutable T* m_p; 00181 mutable OnceFlag m_onceFlag; 00182 }; 00183 00188 #define BLOCXX_LAZY_GLOBAL_INIT(...) { __VA_ARGS__, 0, BLOCXX_ONCE_INIT } 00189 00190 } // end namespace BLOCXX_NAMESPACE 00191 00192 00193 #endif