compilation-bundle/dwarf-compilation.base/contrib/libdwarfpp/include/dwarfpp/opt.hpp

102 lines
3.1 KiB
C++

/* dwarfpp: C++ binding for a useful subset of libdwarf, plus extra goodies.
*
* opt.hpp: utility code for optional data
*
* Copyright (c) 2008--17, Stephen Kell. For licensing information, see the
* LICENSE file in the root of the libdwarfpp tree.
*/
#ifndef DWARFPP_OPT_HPP_
#define DWARFPP_OPT_HPP_
#include <boost/optional.hpp>
#include <memory>
namespace dwarf
{
namespace core
{
struct iterator_base;
struct type_die;
template <typename DerefAs>
struct iterator_df;
}
namespace spec
{
/* FIXME: this stuff arguably doesn't belong in spec, but in a util area. */
/* (So do the exception types we define, like Not_supported and No_entry,
* arguably. FIXME: move those.) */
using std::shared_ptr;
using boost::optional;
/* We use this to encode optional attributes. It's like boost::optional,
* but since pointers already model the optional concept, we avoid a double-
* indirection (**attr) to get the value of a pointer-valued attribute. */
// FIXME: don't hardcode std::shared_ptr here
template <typename T, typename Enabler = void>
struct opt : optional<T>
{
typedef optional<T> super;
// needs g++ 4.8+! or some other C++11-compliant compiler
using optional<T>::optional;
operator bool() const { return this->is_initialized(); }
};
/* END the non-specialised opt<> case. */
/* BEGIN the opt<> case specialized for shared_ptr. */
template <typename T>
struct opt<shared_ptr<T> > : shared_ptr<T>
{
typedef shared_ptr<T> super;
/* forward the underlying constructors */
using shared_ptr<T>::shared_ptr;
operator bool() const { return !!static_cast<const super&>(*this); }
};
/* Similarly, we need one for iterators, i.e. things which extend
* iterator_base. Can we express this specialization? It seems that
* std::enable_if can do this. This is why we need the extra Enabler
* template argument, though. (We could try the more direct approach,
* but the compiler complains that the specialization doesn't name the
* template argument T. I'm not convinced that this complaint is valid.) */
template <typename T>
struct opt< T, typename std::enable_if<std::is_base_of<core::iterator_base, T>::value >::type >
: T
{
typedef T super;
/* forward the underlying constructors */
using T::T;
// operator bool is already taken care of in iterator_base
};
/* These do the opposite: unspecialise, to reinstate the double indirection.
* We only need them in encap.hpp where we have macros
* that want to do attribute_value(*a) for any argument a. Normally the caller
* would know not to do *a, but in that macroised generic code, we can't know.
* So we have the code do *deref_opt(), which no-ops the unwanted deref. */
template <typename T>
std::shared_ptr<T> deref_opt(const opt<shared_ptr<T> >& arg)
{ return arg; }
template <typename T>
T deref_opt(const opt<T>& arg)
{ return *arg; }
template <typename T>
T
deref_opt(const opt< T, typename std::enable_if<std::is_base_of<core::iterator_base, T>::value, T >::type >& arg)
{
return arg;
}
} /* end namespace spec */
}
#endif