#ifndef BOOST_WIN32_ONCE_HPP #define BOOST_WIN32_ONCE_HPP // once.hpp // // (C) Copyright 2005 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include "boost/utility/result_of.hpp" namespace boost { namespace detail { struct result_holder { virtual ~result_holder() {} }; template struct result_holder_impl: result_holder { result_type value; template result_holder_impl(Function f): value(f()) {} }; template<> struct result_holder_impl: result_holder { template result_holder_impl(Function f) { f(); } }; } struct once_flag { LONG flag; ::boost::detail::result_holder* result; ~once_flag() { delete result; } }; #define BOOST_ONCE_INIT {0} namespace detail { std::string create_unique_name(void* p,const char* tag) { std::ostringstream res; res<<"unique-"< result_type get_result(result_holder* holder) { typedef ::boost::detail::result_holder_impl holder_type; return dynamic_cast(holder)->value; } template<> void get_result(result_holder* holder) { } } template typename ::boost::result_of::type call_once(Function f,once_flag& flag) { typedef typename ::boost::result_of::type result_type; LONG const function_complete_flag_value=0xc15730e2; if(!::InterlockedCompareExchange(&flag.flag,function_complete_flag_value, function_complete_flag_value)) { std::string const once_mutex_name=detail::create_unique_name(&flag,"once_init"); HANDLE const mutex_handle(::CreateMutex(NULL,0,once_mutex_name.c_str())); if(!mutex_handle) { abort(); } detail::handle_closer const closer(mutex_handle); ::WaitForSingleObject(mutex_handle,INFINITE); detail::mutex_releaser const releaser(mutex_handle); if(!::InterlockedCompareExchange(&flag.flag,function_complete_flag_value, function_complete_flag_value)) { typedef ::boost::detail::result_holder_impl holder_type; flag.result=new holder_type(f); ::InterlockedExchange(&flag.flag,function_complete_flag_value); } } return ::boost::detail::get_result(flag.result); } } #endif