//Copyright (c) 2007 Joshua Napoli //Based on Emil Dotchevski's exception library. //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) #ifndef BOOST_EXCEPTION_HPP #define BOOST_EXCEPTION_HPP #include #include #include #include #include #include namespace boost { namespace error { class exception; class error_info_visitor_base { public: virtual ~error_info_visitor_base() {} }; template class error_info_visitor : public error_info_visitor_base { public: virtual void apply(const T& t) const=0; virtual ~error_info_visitor() {} }; namespace exception_detail { class error_info_base { public: virtual std::ostream& format(std::ostream& os) const throw()=0; virtual void visit(const error_info_visitor_base&) const=0; virtual ~error_info_base() {} }; template struct packed_array { typename boost::remove_const::type t_; packed_array(const T& t) { std::copy(&t[0],&t[extent::value],&t_[0]); } }; template::value> struct pack { typedef T result_type; result_type operator()(const T& t) const {return t;} }; template struct pack { typedef packed_array result_type; result_type operator()(const T& t) const {return result_type(t);} }; template::value> struct unpack { typedef T result_type; const result_type& operator()(const T& t) const {return t;} }; template struct unpack { typedef T result_type; const result_type& operator()(const packed_array& t) const { return t.t_; } }; template struct print { template std::basic_ostream& operator() (std::basic_ostream& os, const T& t) { return os << t; } }; template struct apply_error_visitor { void operator()(const error_info_visitor_base& v, const T& t) const { const error_info_visitor* visitor(dynamic_cast*>(&v)); if(visitor) { visitor->apply(t); } } }; template class error_info_list : public error_info_base { public: error_info_list(const shared_ptr& head, const Tail& tail) :head_(head) ,tail_(pack()(tail)) {} virtual std::ostream& format(std::ostream& os) const throw() { if(head_) return print()(head_->format(os),unpack()(tail_)); else return print()(os,unpack()(tail_)); } virtual void visit(const error_info_visitor_base& v) const { if(head_) head_->visit(v); apply_error_visitor()(v,unpack()(tail_)); } virtual ~error_info_list() {} private: shared_ptr head_; typename pack::result_type tail_; }; } class exception { public: exception() throw() {} exception(const exception& other) throw() :info_(other.info_) {} ///a default message is provided if the formatting fails virtual const char* what() const throw() { try { std::stringstream s; if(info_) info_->format(s); what_.reset(new std::string(s.str())); return what_->c_str(); } catch(...) { static const char default_message[]="error while formatting the exception message"; return default_message; } } ///only throws if the visitor throws void visit(const error_info_visitor_base& v) const { if(info_) info_->visit(v); } ///has no effect, if the operation fails template void set(const T&t) throw() { try { info_.reset(new exception_detail::error_info_list(info_,t)); } catch(...) {} } ///exceptions thrown by destructor of contained values are ignored virtual ~exception() throw() { boost::shared_ptr info; info_.swap(info); try { info.reset(); } catch(...) {} } private: shared_ptr info_; mutable shared_ptr what_; }; template E operator<< (const E& e,const T& t) { E retval(e); retval.set(t); return retval; } template E& operator<< (E& e,const T& t) { e.set(t); return e; } namespace exception_detail { template<> struct print { template std::basic_ostream& operator() (std::basic_ostream& os, const exception& e) { return os << e.what(); } }; template<> struct apply_error_visitor { void operator()(const error_info_visitor_base& v, const exception& e) const { e.visit(v); } }; } }//namespace error typedef error::exception exception; template struct error_info_value { typedef T type; }; template struct error_info { typename Tag::type t_; error_info(const typename Tag::type& t) : t_(t) {} }; template std::basic_ostream& operator<< (std::basic_ostream& os, const error_info& t) { return os << t.t_; } template struct error_info_field_visitor : error::error_info_visitor { F f_; error_info_field_visitor(F f) : f_(f) {} virtual void apply(const ErrorInfo& info) const { f_(info.t_); } virtual ~error_info_field_visitor() {} }; template struct field_visitor : error::error_info_visitor { F f_; field_visitor(F f) : f_(f) {} virtual void apply(const T& t) const { f_(t); } virtual ~field_visitor() {} }; template error_info_field_visitor,F> on_error_info(Tag, F f) { return error_info_field_visitor,F>(f); } template field_visitor on_error_info(F f) { return field_visitor(f); } } #endif