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