• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Support for interoperability between Boost.System and <system_error>
2 //
3 // Copyright 2018 Peter Dimov
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // See library home page at http://www.boost.org/libs/system
9 
10 #include <system_error>
11 #include <map>
12 #include <memory>
13 #include <mutex>
14 
15 //
16 
17 namespace boost
18 {
19 
20 namespace system
21 {
22 
23 namespace detail
24 {
25 
26 class BOOST_SYMBOL_VISIBLE std_category: public std::error_category
27 {
28 private:
29 
30     boost::system::error_category const * pc_;
31 
32 public:
33 
std_category(boost::system::error_category const * pc,unsigned id)34     explicit std_category( boost::system::error_category const * pc, unsigned id ): pc_( pc )
35     {
36         if( id != 0 )
37         {
38 #if defined(_MSC_VER) && defined(_CPPLIB_VER) && _MSC_VER >= 1900 && _MSC_VER < 2000
39 
40             // Poking into the protected _Addr member of std::error_category
41             // is not a particularly good programming practice, but what can
42             // you do
43 
44             _Addr = id;
45 
46 #endif
47         }
48     }
49 
name() const50     const char * name() const BOOST_NOEXCEPT BOOST_OVERRIDE
51     {
52         return pc_->name();
53     }
54 
message(int ev) const55     std::string message( int ev ) const BOOST_OVERRIDE
56     {
57         return pc_->message( ev );
58     }
59 
default_error_condition(int ev) const60     std::error_condition default_error_condition( int ev ) const BOOST_NOEXCEPT BOOST_OVERRIDE
61     {
62         return pc_->default_error_condition( ev );
63     }
64 
65     bool equivalent( int code, const std::error_condition & condition ) const BOOST_NOEXCEPT BOOST_OVERRIDE;
66     bool equivalent( const std::error_code & code, int condition ) const BOOST_NOEXCEPT BOOST_OVERRIDE;
67 };
68 
69 #if !defined(__SUNPRO_CC) // trailing __global is not supported
70 inline std::error_category const & to_std_category( boost::system::error_category const & cat ) BOOST_SYMBOL_VISIBLE;
71 #endif
72 
73 struct cat_ptr_less
74 {
operator ()boost::system::detail::cat_ptr_less75     bool operator()( boost::system::error_category const * p1, boost::system::error_category const * p2 ) const BOOST_NOEXCEPT
76     {
77         return *p1 < *p2;
78     }
79 };
80 
to_std_category(boost::system::error_category const & cat)81 inline std::error_category const & to_std_category( boost::system::error_category const & cat )
82 {
83     if( cat == boost::system::system_category() )
84     {
85         static const std_category system_instance( &cat, 0x1F4D7 );
86         return system_instance;
87     }
88     else if( cat == boost::system::generic_category() )
89     {
90         static const std_category generic_instance( &cat, 0x1F4D3 );
91         return generic_instance;
92     }
93     else
94     {
95         typedef std::map< boost::system::error_category const *, std::unique_ptr<std_category>, cat_ptr_less > map_type;
96 
97         static map_type map_;
98         static std::mutex map_mx_;
99 
100         std::lock_guard<std::mutex> guard( map_mx_ );
101 
102         map_type::iterator i = map_.find( &cat );
103 
104         if( i == map_.end() )
105         {
106             std::unique_ptr<std_category> p( new std_category( &cat, 0 ) );
107 
108             std::pair<map_type::iterator, bool> r = map_.insert( map_type::value_type( &cat, std::move( p ) ) );
109 
110             i = r.first;
111         }
112 
113         return *i->second;
114     }
115 }
116 
equivalent(int code,const std::error_condition & condition) const117 inline bool std_category::equivalent( int code, const std::error_condition & condition ) const BOOST_NOEXCEPT
118 {
119     if( condition.category() == *this )
120     {
121         boost::system::error_condition bn( condition.value(), *pc_ );
122         return pc_->equivalent( code, bn );
123     }
124     else if( condition.category() == std::generic_category() || condition.category() == boost::system::generic_category() )
125     {
126         boost::system::error_condition bn( condition.value(), boost::system::generic_category() );
127         return pc_->equivalent( code, bn );
128     }
129 
130 #ifndef BOOST_NO_RTTI
131 
132     else if( std_category const* pc2 = dynamic_cast< std_category const* >( &condition.category() ) )
133     {
134         boost::system::error_condition bn( condition.value(), *pc2->pc_ );
135         return pc_->equivalent( code, bn );
136     }
137 
138 #endif
139 
140     else
141     {
142         return default_error_condition( code ) == condition;
143     }
144 }
145 
equivalent(const std::error_code & code,int condition) const146 inline bool std_category::equivalent( const std::error_code & code, int condition ) const BOOST_NOEXCEPT
147 {
148     if( code.category() == *this )
149     {
150         boost::system::error_code bc( code.value(), *pc_ );
151         return pc_->equivalent( bc, condition );
152     }
153     else if( code.category() == std::generic_category() || code.category() == boost::system::generic_category() )
154     {
155         boost::system::error_code bc( code.value(), boost::system::generic_category() );
156         return pc_->equivalent( bc, condition );
157     }
158 
159 #ifndef BOOST_NO_RTTI
160 
161     else if( std_category const* pc2 = dynamic_cast< std_category const* >( &code.category() ) )
162     {
163         boost::system::error_code bc( code.value(), *pc2->pc_ );
164         return pc_->equivalent( bc, condition );
165     }
166 #endif
167 
168     else if( *pc_ == boost::system::generic_category() )
169     {
170         return std::generic_category().equivalent( code, condition );
171     }
172     else
173     {
174         return false;
175     }
176 }
177 
178 } // namespace detail
179 
180 } // namespace system
181 
182 } // namespace boost
183