Files
mlpack/fastlib/trilinos/include/Teuchos_any.hpp
T

332 lines
9.1 KiB
C++

#ifndef TEUCHOS_ANY_HPP
#define TEUCHOS_ANY_HPP
/*! \file Teuchos_any.hpp
\brief Modified boost::any class for holding a templated value
*/
#include "Teuchos_TestForException.hpp"
#include "Teuchos_TypeNameTraits.hpp"
//
// This file was taken from the boost library which contained the
// following notice:
//
// *************************************************************
//
// what: variant type boost::any
// who: contributed by Kevlin Henney,
// with features contributed and bugs found by
// Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when: July 2001
// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
//
// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.
//
// *************************************************************
//
// RAB modified the file for use in Teuchos. I changed the nature of
// the any_cast<> to be easier to use.
//
namespace Teuchos {
/** \brief Modified boost::any class, which is a container for a templated
* value.
*/
class any
{
public:
//! Empty constructor
any()
: content(0)
{}
//! Templated constructor
template<typename ValueType>
explicit any(const ValueType & value)
: content(new holder<ValueType>(value))
{}
//! Copy constructor
any(const any & other)
: content(other.content ? other.content->clone() : 0)
{}
//! Destructor
~any()
{
delete content;
}
//! Method for swapping the contents of two any classes
any & swap(any & rhs)
{
std::swap(content, rhs.content);
return *this;
}
//! Copy the value <tt>rhs</tt>
template<typename ValueType>
any & operator=(const ValueType & rhs)
{
any(rhs).swap(*this);
return *this;
}
//! Copy the value held in <tt>rhs</tt>
any & operator=(const any & rhs)
{
any(rhs).swap(*this);
return *this;
}
//! Return true if nothing is being stored
bool empty() const
{
return !content;
}
//! Return the type of value being stored
const std::type_info & type() const
{
return content ? content->type() : typeid(void);
}
//! Return the name of the type
std::string typeName() const
{
return content ? content->typeName() : "NONE";
}
//! \brief Return if two any objects are the same or not.
bool same( const any &other ) const
{
if( this->empty() && other.empty() )
return true;
else if( this->empty() && !other.empty() )
return false;
else if( !this->empty() && other.empty() )
return false;
// !this->empty() && !other.empty()
return content->same(*other.content);
}
//! Print this value to the output stream <tt>os</tt>
void print(std::ostream& os) const
{
if (content) content->print(os);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/** @name Private??? types */
//@{
/** \brief . */
class placeholder
{
public:
/** \brief . */
virtual ~placeholder() {}
/** \brief . */
virtual const std::type_info & type() const = 0;
/** \brief . */
virtual std::string typeName() const = 0;
/** \brief . */
virtual placeholder * clone() const = 0;
/** \brief . */
virtual bool same( const placeholder &other ) const = 0;
/** \brief . */
virtual void print(std::ostream & os) const = 0;
};
/** \brief . */
template<typename ValueType>
class holder : public placeholder
{
public:
/** \brief . */
holder(const ValueType & value)
: held(value)
{}
/** \brief . */
const std::type_info & type() const
{ return typeid(ValueType); }
/** \brief . */
std::string typeName() const
{ return TypeNameTraits<ValueType>::name(); }
/** \brief . */
placeholder * clone() const
{ return new holder(held); }
/** \brief . */
bool same( const placeholder &other ) const
{
if( type() != other.type() ) {
return false;
}
// type() == other.type()
const ValueType
&other_held = dynamic_cast<const holder<ValueType>&>(other).held;
return held == other_held;
}
/** \brief . */
void print(std::ostream & os) const
{ os << held; }
/** \brief . */
ValueType held;
};
//@}
public:
// Danger: This is made public to allow any_cast to be non-friend
placeholder* access_content()
{ return content; }
const placeholder* access_content() const
{ return content; }
#endif
private:
// /////////////////////////
// Private data members
placeholder * content;
};
/*! \relates any
\brief Thrown if any_cast is attempted between two incompatable types.
*/
class bad_any_cast : public std::runtime_error
{
public:
bad_any_cast( const std::string msg ) : std::runtime_error(msg) {}
};
/*! \relates any
\brief Used to extract the templated value held in Teuchos::any to a given value type.
\note <ul> <li> If the templated value type and templated type are not the same then a
bad_any_cast is thrown.
<li> If the dynamic cast fails, then a Teuchos::bad_any_cast std::exception is thrown.
</ul>
*/
template<typename ValueType>
ValueType& any_cast(any &operand)
{
const std::string ValueTypeName = TypeNameTraits<ValueType>::name();
bool type_mismatch = ( operand.type() != typeid(ValueType) );
#ifdef HAVE_SHARED
// For shared libraries, the above may resolve as true because one
// of the types is not fully qualified. The following check will
// compensate for that.
if ( type_mismatch )
type_mismatch = ( strcmp(operand.type().name(), typeid(ValueType).name()) != 0 );
#endif
TEST_FOR_EXCEPTION(
type_mismatch, bad_any_cast
,"any_cast<"<<ValueTypeName<<">(operand): Error, cast to type "
<< "any::holder<"<<ValueTypeName<<"> failed since the actual underlying type is \'"
<< typeName(*operand.access_content()) << "!"
);
TEST_FOR_EXCEPTION(
!operand.access_content(), bad_any_cast
,"any_cast<"<<ValueTypeName<<">(operand): Error, cast to type "
<< "any::holder<"<<ValueTypeName<<"> failed because the content is NULL"
);
// 2007/11/28: rabartl: Note: If we get here, then the rest of this function
// should succeed and should be a formality. The dynamic cast is the safe
// thing to do and therefore we try that. However, this may actually fail
// with shared libraries with g++ (see below).
any::holder<ValueType>
*dyn_cast_content = dynamic_cast<any::holder<ValueType>*>(operand.access_content());
#ifdef HAVE_SHARED
// For shared libraries, dynamic_cast does not work across shared
// library boundaries, so we use static_cast, which will prevent any
// runtime errors at the expense of being more dangerous.
if ( !dyn_cast_content )
dyn_cast_content = static_cast<any::holder<ValueType>*>(operand.access_content());
// 2007/11/28: rabartl: Above, this static cast is not safe for some
// possible types but that should be very rare. Note that if a program
// performing the dynamic casts works correctly with a static library
// (i.e. HAVE_SHARED is not defined), and if the compiler can figure out the
// static case correctly, then this should be safe for the shared library
// case. We really need to look into issues of RTTI and shared libraries
// and see what the C++ standard says about this and if there are any g++
// command-line options for fixing this ...
#endif
TEST_FOR_EXCEPTION(
!dyn_cast_content, std::logic_error
,"any_cast<"<<ValueTypeName <<">(operand): Error, cast to type "
<< "any::holder<"<<ValueTypeName<<"> failed but should not have and the actual underlying type is \'"
<< typeName(*operand.access_content()) << "!"
);
return dyn_cast_content->held;
}
/*! \relates any
\brief Used to extract the const templated value held in Teuchos::any to a given
const value type.
\note <ul> <li> If the templated value type and templated type are not the same then
bad_any_cast is thrown.
<li> If the dynamic cast fails, then a logic_error is thrown.
</ul>
*/
template<typename ValueType>
const ValueType& any_cast(const any &operand)
{
return any_cast<ValueType>(const_cast<any&>(operand));
}
/*! \relates any
\brief Converts the value in <tt>any</tt> to a std::string.
*/
inline std::string toString(const any &rhs)
{
std::ostringstream oss;
rhs.print(oss);
return oss.str();
}
/*! \relates any
\brief Returns true if two any objects have the same value.
*/
inline bool operator==( const any &a, const any &b )
{
return a.same(b);
}
/*! \relates any
\brief Returns true if two any objects <b>do not</tt> have the same value.
*/
inline bool operator!=( const any &a, const any &b )
{
return !a.same(b);
}
/*! \relates any
\brief Writes "any" input <tt>rhs</tt> to the output stream <tt>os</tt>.
*/
inline std::ostream & operator<<(std::ostream & os, const any &rhs)
{
rhs.print(os);
return os;
}
} // namespace Teuchos
#endif // TEUCHOS_ANY_HPP