neuray API Programmer's Manual

handle.h File Reference

Description

Smart-pointer handle class for interfaces, const and non-const version.

Code Example

handle.h

‎/***************************************************************************************************
 * Copyright 2023 NVIDIA Corporation. All rights reserved.
 **************************************************************************************************/

#ifndef MI_BASE_HANDLE_H
#define MI_BASE_HANDLE_H

#include <mi/base/assert.h>
#include <mi/base/config.h> // for MI_CXX_FEATURE_RVALUE_REFERENCES
#include <mi/base/iinterface.h>

#ifdef __cpp_variadic_templates
#include <utility>
#endif


namespace mi {
namespace base {

// Helper type to define Dup_interface
struct Dup_interface_helper {};

typedef const Dup_interface_helper* Dup_interface;

static const Dup_interface 
               DUP_INTERFACE = 0;

template <class Interface>
class Handle
{
public:
    typedef Handle< Interface> 
               Self;

    typedef Interface Interface_type;

    // STL iterator inspired typedef names

    typedef Interface  value_type;

    typedef Difference 
               difference_type;

    typedef Interface* pointer;

    typedef Interface& reference;

private:
    template <typename I2> friend class Handle;

    // Pointer to underlying interface, can be \c NULL
    Interface* m_iptr;

public:
    Handle() : m_iptr( 0) { }

    explicit Handle( Interface* ptr) : m_iptr( ptr) { }

    Handle( Interface* ptr, Dup_interface)
      : m_iptr( ptr)
    {
        if( m_iptr)
            m_iptr->retain();
    }

    Handle( const Self& other)
      : m_iptr( other.m_iptr)
    {
        if( m_iptr)
            m_iptr->retain();
    }

    template <class Interface2>
    Handle( const Handle< Interface2>& other)
      : m_iptr( other.get())
    {
        if( m_iptr)
            m_iptr->retain();
    }

#ifdef MI_CXX_FEATURE_RVALUE_REFERENCES
    Handle( Self&& other)
      : m_iptr( other.m_iptr)
    {
        other.m_iptr = 0;
    }

    template <class Interface2>
    Handle( Handle<Interface2>&& other)
      : m_iptr( other.m_iptr)
    {
        other.m_iptr = 0;
    }
#endif

    void swap( Self& other)
    {
        Interface* tmp_iptr = m_iptr;
        m_iptr = other.m_iptr;
        other.m_iptr = tmp_iptr;
    }

    Self& operator=( const Self& other)
    {
        Self( other).swap( *this);
        return *this;
    }

    template <class Interface2>
    Self& operator=( const Handle< Interface2>& other)
    {
        Self( other).swap( *this);
        return *this;
    }

#ifdef MI_CXX_FEATURE_RVALUE_REFERENCES
    Self& operator=( Self&& other)
    {
        if( this != &other) {
            if( m_iptr)
                m_iptr->release();
            m_iptr = other.m_iptr;
            other.m_iptr = 0;
        }
        return *this;
    }

    template <class Interface2>
    Self& operator=( Handle<Interface2>&& other)
    {
        if( m_iptr)
            m_iptr->release();
        m_iptr = other.m_iptr;
        other.m_iptr = 0;

        return *this;
    }
#endif

    Self& operator=( Interface* ptr)
    {
        Self( ptr).swap( *this);
        return *this;
    }

    void reset()
    {
        if( m_iptr) {
            m_iptr->release();
            m_iptr = 0;
        }
    }

    ~Handle()
    {
        if( m_iptr)
            m_iptr->release();
    }

    bool is_valid_interface() const { return m_iptr != 0; }

    Interface* get() const { return  m_iptr; }

    Interface* extract()
    {
        Interface* ptr = m_iptr;
        m_iptr = 0;
        return ptr;
    }

#ifdef __cpp_variadic_templates
    template <typename... T>
    Self& emplace(T&&... args)
    {
        return emplace<Interface>(std::forward<T>(args)...);
    }

    template <typename Impl, typename... T>
    Self& emplace(T&&... args)
    {
        reset();
        m_iptr = new Impl(std::forward<T>(args)...);
        return *this;
    }
#endif

    Interface& operator*() const
    {
        mi_base_assert_msg( is_valid_interface(), "precondition");
        return *m_iptr;
    }

    Interface* operator->() const
    {
        mi_base_assert_msg( is_valid_interface(), "precondition");
        return m_iptr;
    }

    template <class New_interface>
    Handle< New_interface> 
               get_interface() const
    {
        if( !is_valid_interface())
            return Handle< New_interface>( 0);
        return Handle< New_interface>( static_cast< New_interface*>(
            m_iptr->get_interface( typename New_interface::IID())));
    }

    typedef bool (Handle::*bool_conversion_support)() const;

    operator bool_conversion_support() const
    {
        return is_valid_interface() ? &Handle< Interface>::is_valid_interface : 0;
    }

    friend bool operator==( const Handle< Interface>& lhs, const Interface* rhs)
    {
        return lhs.get() == rhs;
    }

    friend bool operator==( const Interface* lhs, const Handle< Interface>& rhs)
    {
        return lhs == rhs.get();
    }

    friend bool operator!=( const Handle< Interface>& lhs, const Interface* rhs)
    {
        return !( lhs == rhs);
    }

    friend bool operator!=( const Interface* lhs, const Handle< Interface>& rhs) {
        return !( lhs == rhs);
    }
};

template <class Interface1, class Interface2>
inline bool operator==( const Handle< Interface1>& lhs, const Handle< Interface2>& rhs)
{
    return lhs.get() == rhs.get();
}

template <class Interface1, class Interface2>
inline bool operator!=( const Handle< Interface1>& lhs, const Handle< Interface2>& rhs)
{
    return !( lhs == rhs);
}

template <class Interface>
inline Handle< Interface> 
               make_handle( Interface* iptr)
{
    return Handle< Interface>( iptr);
}

template <class Interface>
inline Handle< Interface> 
               make_handle_dup( Interface* iptr)
{
    return Handle< Interface>( iptr, DUP_INTERFACE);
}

#ifdef __cpp_variadic_templates
template <typename Impl, typename... T>
inline Handle<Impl> construct_handle(T&&... args)
{
    return Handle<Impl>{new Impl(std::forward<T>(args)...)};
}

#endif

 // end group mi_base_iinterface

} // namespace base
} // namespace mi

#endif // MI_BASE_HANDLE_H

Namespaces

namespace 
Common namespace for APIs of NVIDIA Advanced Rendering Center GmbH. More...
namespace 
Namespace for the Base API. More...

Classes

class 
Handle class template for interfaces, automatizing the lifetime control via reference counting. More...

Typedefs

typedef Dup_interface_helper *  
Type for a symbolic constant to trigger a special constructor in the Handle class. More...

Functions

template< class Interface> Handle < Interface >  ( Interface* iptr)
Returns a handle that holds the interface pointer passed in as argument. More...
template< class Interface> Handle < Interface >  ( Interface* iptr)
Converts passed-in interface pointer to a handle, without taking interface over. More...
template< class Interface1, class Interface2>bool   ( const Handle < Interface1 >& lhs, const Handle < Interface2 >& rhs)
Returns true if the underlying interface pointers are not equal. More...
template< class Interface1, class Interface2>bool   ( const Handle < Interface1 >& lhs, const Handle < Interface2 >& rhs)
Returns true if the underlying interface pointers are equal. More...

Variables

static const Dup_interface  
Symbolic constant to trigger a special constructor in the Handle class. More...