102 lines
3.1 KiB
C++
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
|