// **********************************************************************
//
// Copyright (c) 2002
// IONA Technologies, Inc.
// Waltham, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#ifndef OB_TEMPLATE_H
#define OB_TEMPLATE_H

#include <OB/Basic.h>

namespace OB
{

//
// Declare InputStreamImpl and OutputStreamImpl
//
class InputStreamImpl;
class OutputStreamImpl;

//
// Forward declaration (throw CORBA::NO_MEMORY exception, it's defined
// here to break the circular dependency between Except.h and
// Template.h)
//
void ThrowNoMemoryException(); // See Except.cpp

// ----------------------------------------------------------------------
// T_var templates
// ----------------------------------------------------------------------

//
// T_var template for fixed-length general data types
//
template<class T>
class FixVar
{
    T* ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    FixVar() : ptr_(0) { }
    FixVar(T* p) : ptr_(p) { assert_nca(p != 0, NCANullInit); }
    FixVar(const T& r) : ptr_(new T(r)) { }
#ifdef HAVE_VCPLUSPLUS_BUGS
    FixVar(const FixVar<T>& r)
    { ptr_ = r.ptr_ ? new T(*r.ptr_) : 0 ; }
#else
    FixVar(const FixVar<T>& r)
        : ptr_(r.ptr_ ? new T(*r.ptr_) : 0) { }
#endif
    ~FixVar() { delete ptr_; }

    FixVar<T>& operator=(T*);
    FixVar<T>& operator=(const T&);
    FixVar<T>& operator=(const FixVar<T>&);

#ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
#else
    T* operator->() { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
    const T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
#endif

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#   else
    operator const T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    operator T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#   endif
#endif

    const T& in() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    T& inout() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    T& out()
    {
        if(ptr_ == 0)
            ptr_ = new T;
        return *ptr_;
    }
    const T& _retn() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T*& ptr() { return ptr_; }
};

//
// T_var template for variable-length general data types
//
template<class T> class VarOut;

template<class T>
class VarVar
{
    friend class VarOut<T>;
    T* ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    VarVar() : ptr_(0) { }
    VarVar(T* p) : ptr_(p) { assert_nca(p != 0, NCANullInit); }
#ifdef HAVE_VCPLUSPLUS_BUGS
    VarVar(const VarVar<T>& r)
    { ptr_ = r.ptr_ ? new T(*r.ptr_) : 0 ; }
#else
    VarVar(const VarVar<T>& r)
        : ptr_(r.ptr_ ? new T(*r.ptr_) : 0) { }
#endif
    ~VarVar() { delete ptr_; }

    VarVar<T>& operator=(T*);
    VarVar<T>& operator=(const VarVar<T>&);

#ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
#else
    T* operator->() { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
    const T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
#endif

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#   else
    operator const T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    operator T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#   endif
    operator T*&() { return ptr_; }
#endif

    const T& in() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    T& inout() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    T*& out() { delete ptr_; ptr_ = 0; return ptr_; }
    T* _retn() { T* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T*& ptr() { return ptr_; }
};

//
// T_var template for sequence types
//
template <class T> class SeqOut;

template<class T>
class SeqVar
{
    friend class SeqOut<T>;
    T* ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    SeqVar() : ptr_(0) { }
    SeqVar(T* p) : ptr_(p) { assert_nca(p != 0, NCANullInit); }
#ifdef HAVE_VCPLUSPLUS_BUGS
    SeqVar(const SeqVar<T>& r)
    { ptr_ = r.ptr_ ? new T(*r.ptr_) : 0 ; }
#else
    SeqVar(const SeqVar<T>& r)
        : ptr_(r.ptr_ ? new T(*r.ptr_) : 0) { }
#endif
    ~SeqVar() { delete ptr_; }

    SeqVar<T>& operator=(T*);
    SeqVar<T>& operator=(const SeqVar<T>&);

#ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
#else
    T* operator->() { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
    const T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }
#endif

#ifdef HAVE_NO_TYPENAME
    typedef T::SubType SubType;
    typedef T::ConstSubType ConstSubType;
#else
    typedef typename T::SubType SubType;
    typedef typename T::ConstSubType ConstSubType;
#endif

    SubType operator[](short idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](unsigned short idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
#if defined(HAVE_VCPLUSPLUS_BUGS) && !defined(__BORLANDC__)
    ConstSubType operator[](short idx) const
    { assert_nca(ptr_ != 0, NCANullPtr);
      return (ConstSubType)(ptr_ -> operator[](idx)); }
    ConstSubType operator[](unsigned short idx) const
    { assert_nca(ptr_ != 0, NCANullPtr);
      return (ConstSubType)(ptr_ -> operator[](idx)); }
#else
    ConstSubType operator[](short idx) const
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    ConstSubType operator[](unsigned short idx) const
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
#endif

    SubType operator[](int idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](unsigned int idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
#if defined(HAVE_VCPLUSPLUS_BUGS) && !defined(__BORLANDC__)
    ConstSubType operator[](int idx) const
    { assert_nca(ptr_ != 0, NCANullPtr);
      return (ConstSubType)(ptr_ -> operator[](idx)); }
    ConstSubType operator[](unsigned int idx) const
    { assert_nca(ptr_ != 0, NCANullPtr);
      return (ConstSubType)(ptr_ -> operator[](idx)); }
#else
    ConstSubType operator[](int idx) const
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    ConstSubType operator[](unsigned int idx) const
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
#endif

    SubType operator[](long idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](unsigned long idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
#if defined(HAVE_VCPLUSPLUS_BUGS) && !defined(__BORLANDC__)
    ConstSubType operator[](long idx) const
    { assert_nca(ptr_ != 0, NCANullPtr);
      return (ConstSubType)(ptr_ -> operator[](idx)); }
    ConstSubType operator[](unsigned long idx) const
    { assert_nca(ptr_ != 0, NCANullPtr);
      return (ConstSubType)(ptr_ -> operator[](idx)); }
#else
    ConstSubType operator[](long idx) const
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    ConstSubType operator[](unsigned long idx) const
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
#endif

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#   else
    operator const T&() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    operator T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#   endif
    operator T*&() { return ptr_; }
#endif

    const T& in() const { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    T& inout() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    T*& out() { delete ptr_; ptr_ = 0; return ptr_; }
    T* _retn() { T* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T*& ptr() { return ptr_; }
};

//
// T_var template for fixed-length array types
//
template<class T_slice, class T, CORBA::ULong n>
class FixArrayVar
{
    T_slice* ptr_;

public:

    FixArrayVar() : ptr_(0) { }
    FixArrayVar(T_slice* p) : ptr_(p) { assert_nca(p != 0, NCANullInit); }
    FixArrayVar(const FixArrayVar<T_slice, T, n>&);
    ~FixArrayVar() { delete [] (T*) ptr_; }

    FixArrayVar<T_slice, T, n>& operator=(T_slice*);
    FixArrayVar<T_slice, T, n>&
    operator=(const FixArrayVar<T_slice, T, n>&);

    T_slice& operator[](short idx) { return ptr_[idx]; }
    const T_slice& operator[](short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned short idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](int idx) { return ptr_[idx]; }
    const T_slice& operator[](int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned int idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](long idx) { return ptr_[idx]; }
    const T_slice& operator[](long idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned long idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned long idx) const
    { return ((const T_slice*)ptr_)[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
#   ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#   else
    operator const T_slice*() const { return ptr_; }
#   endif
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T_slice*() const { return ptr_; }
#   else
#       ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#       else
    operator const T_slice*() const { return ptr_; }
#       endif
    operator T_slice*() { return ptr_; }
#   endif
#endif

#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_slice* in() const { return (const T_slice*)ptr_; }
#else
    const T_slice* in() const { return ptr_; }
#endif
    T_slice* inout() { return ptr_; }
    T_slice* out() { delete [] (T*) ptr_; ptr_ = 0; return ptr_; }
    T_slice* _retn() { T_slice* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T_slice* ptr() { return ptr_; }
};

//
// T_var template for variable-length array types
//
template<class T_slice, class T, CORBA::ULong n> class VarArrayOut;

template<class T_slice, class T, CORBA::ULong n>
class VarArrayVar
{
    friend class VarArrayOut<T_slice, T, n>;
    T_slice* ptr_;

public:

    VarArrayVar() : ptr_(0) { }
    VarArrayVar(T_slice* p) : ptr_(p) { assert_nca(p != 0, NCANullInit); }
    VarArrayVar(const VarArrayVar<T_slice, T, n>&);
    ~VarArrayVar() { delete [] (T*) ptr_; }

    VarArrayVar<T_slice, T, n>& operator=(T_slice*);
    VarArrayVar<T_slice, T, n>&
    operator=(const VarArrayVar<T_slice, T, n>&);

    T_slice& operator[](short idx) { return ptr_[idx]; }
    const T_slice& operator[](short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned short idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](int idx) { return ptr_[idx]; }
    const T_slice& operator[](int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned int idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](long idx) { return ptr_[idx]; }
    const T_slice& operator[](long idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned long idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned long idx) const
    { return ((const T_slice*)ptr_)[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
#   ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#   else
    operator const T_slice*() const { return ptr_; }
#   endif
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T_slice*&() const { return (T_slice*&)ptr_; }
#   else
#       ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#       else
    operator const T_slice*() const { return ptr_; }
#       endif
    operator T_slice*&() { return ptr_; }
#   endif
#endif

#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_slice* in() const { return (const T_slice*)ptr_; }
#else
    const T_slice* in() const { return ptr_; }
#endif
    T_slice* inout() { return ptr_; }
    T_slice*& out() { delete [] (T*) ptr_; ptr_ = 0; return ptr_; }
    T_slice* _retn() { T_slice* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T_slice* ptr() { return ptr_; }
};

//
// Template for fixed-length array forany types
//
template<class T_slice, class T, CORBA::ULong n, class U>
class FixArrayForAny
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    T_slice* ptr_;
    CORBA::Boolean nocopy_;

public:

    FixArrayForAny() : ptr_(0), nocopy_(false) { }
    FixArrayForAny(T_slice* p, CORBA::Boolean nc = false)
        : ptr_(p), nocopy_(nc) { };
    FixArrayForAny(const FixArrayForAny<T_slice, T, n, U>& r,
                  CORBA::Boolean nc = false)
        : ptr_(r.ptr_), nocopy_(nc) { };

    CORBA::Boolean nocopy() const { return nocopy_; }

    FixArrayForAny<T_slice, T, n, U>& operator=(T_slice* p)
    { ptr_ = p; return *this; }
    FixArrayForAny<T_slice, T, n, U>&
    operator=(const FixArrayForAny<T_slice, T, n, U>& r)
    { ptr_ = r.ptr_; return *this; }

    T_slice& operator[](short idx) { return ptr_[idx]; }
    const T_slice& operator[](short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned short idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](int idx) { return ptr_[idx]; }
    const T_slice& operator[](int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned int idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](long idx) { return ptr_[idx]; }
    const T_slice& operator[](long idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned long idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned long idx) const
    { return ((const T_slice*)ptr_)[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
#   ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#   else
    operator const T_slice*() const { return ptr_; }
#   endif
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T_slice*() const { return ptr_; }
#   else
#       ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#       else
    operator const T_slice*() const { return ptr_; }
#       endif
    operator T_slice*() { return ptr_; }
#   endif
#endif

#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_slice* in() const { return (const T_slice*)ptr_; }
#else
    const T_slice* in() const { return ptr_; }
#endif
    T_slice* inout() { return ptr_; }
    T_slice* out() { delete [] (T*) ptr_; ptr_ = 0; return ptr_; }
    T_slice* _retn() { T_slice* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T_slice* ptr() { return ptr_; }
};

//
// Template for variable-length array forany types
//
template<class T_slice, class T, CORBA::ULong n, class U>
class VarArrayForAny
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    T_slice* ptr_;
    CORBA::Boolean nocopy_;

public:

    VarArrayForAny() : ptr_(0), nocopy_(false) { }
    VarArrayForAny(T_slice* p, CORBA::Boolean nc = false)
        : ptr_(p), nocopy_(nc) { };
    VarArrayForAny(const VarArrayForAny<T_slice, T, n, U>& r,
                  CORBA::Boolean nc = false)
        : ptr_(r.ptr_), nocopy_(nc) { };

    CORBA::Boolean nocopy() const { return nocopy_; }

    VarArrayForAny<T_slice, T, n, U>& operator=(T_slice* p)
    { ptr_ = p; return *this; }
    VarArrayForAny<T_slice, T, n, U>&
    operator=(const VarArrayForAny<T_slice, T, n, U>& r)
    { ptr_ = r.ptr_; return *this; }

    T_slice& operator[](short idx) { return ptr_[idx]; }
    const T_slice& operator[](short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned short idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned short idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](int idx) { return ptr_[idx]; }
    const T_slice& operator[](int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned int idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned int idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](long idx) { return ptr_[idx]; }
    const T_slice& operator[](long idx) const
    { return ((const T_slice*)ptr_)[idx]; }
    T_slice& operator[](unsigned long idx) { return ptr_[idx]; }
    const T_slice& operator[](unsigned long idx) const
    { return ((const T_slice*)ptr_)[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
#   ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#   else
    operator const T_slice*() const { return ptr_; }
#   endif
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T_slice*&() const { return (T_slice*&)ptr_; }
#   else
#       ifdef HAVE_VCPLUSPLUS_BUGS
    operator const T_slice*() const { return (const T_slice*)ptr_; }
#       else
    operator const T_slice*() const { return ptr_; }
#       endif
    operator T_slice*&() { return ptr_; }
#   endif
#endif

#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_slice* in() const { return (const T_slice*)ptr_; }
#else
    const T_slice* in() const { return ptr_; }
#endif
    T_slice* inout() { return ptr_; }
    T_slice*& out() { delete [] (T*) ptr_; ptr_ = 0; return ptr_; }
    T_slice* _retn() { T_slice* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T_slice* ptr() { return ptr_; }
};

//
// T_var template for object reference data types
//
class ObjBase
{
};

template<class T> class ObjForSeq;
template<class T> class ObjOut;

template<class T>
class ObjVar : public ObjBase
{
    //
    // Make sure that widening between object reference _var types
    // require a call to _duplicate()
    //
    ObjVar(const ObjBase&) { }
    void operator=(const ObjBase&) { }

    //
    // The ObjOut<T> class is our friend, so it can have direct
    // access to the ptr_ member.
    //
    friend class ObjOut<T>;

    T* ptr_;

public:
    //
    // Standard IDL to C++ Mapping
    //
    ObjVar() : ptr_(0) { }
    ObjVar(T* p) : ptr_(p) { }
    ObjVar(const ObjVar<T>& r) : ptr_(r.ptr_) { OBDuplicate(ptr_); }
    ObjVar(const ObjForSeq<T>&);
    ~ObjVar() { OBRelease(ptr_); }

    ObjVar<T>& operator=(T* p)
    {
        T* old = ptr_;
        ptr_ = p;
        OBRelease(old);
        return *this;
    }
    ObjVar<T>& operator=(const ObjVar<T>& r)
    {
        if(r.ptr_ != ptr_)
        {
            T* old = ptr_;
            ptr_ = r.ptr_;
            OBDuplicate(ptr_);
            OBRelease(old);
        }
        return *this;
    }
    ObjVar<T>& operator=(const ObjForSeq<T>&);

    T* operator->() const { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator T*() const { return ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T*&() const { return (T*&)ptr_; }
#   else
    operator T*() const { return ptr_; }
    operator T*&() { return ptr_; }
#   endif
#endif

    T* in() const { return ptr_; }
    T*& inout() { return ptr_; }
    T*& out() { T* old = ptr_; ptr_ = 0; OBRelease(old); return ptr_; }
    T* _retn() { T* ret = ptr_; ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T*& ptr() { return ptr_; }
};

//
// Object reference type used by object reference sequences
//
template<class T>
class ObjForSeq : public ObjBase
{
    //
    // Make sure that widening between object reference _var types
    // require a call to _duplicate()
    //
    void operator=(const ObjBase&) { }
    ObjForSeq(const ObjBase&) { }

    T** ptr_;
    CORBA::Boolean rel_;

public:

    //
    // ORBacus specific constructor that works together with
    // the corresponding sequence type
    //
    ObjForSeq(T** p, CORBA::Boolean rel) : ptr_(p), rel_(rel) { }
    ObjForSeq(const ObjForSeq<T>& r) : ptr_(r.ptr_), rel_(r.rel_) { }

    //
    // Standard IDL to C++ Mapping
    //
    ObjForSeq<T>& operator=(T* p)
    {
        if(rel_)
        {
            T* old = *ptr_;
            *ptr_ = p;
            OBRelease(old);
        }
        else
            *ptr_ = p;
        return *this;
    }
    ObjForSeq<T>& operator=(const ObjVar<T>& r)
    {
        if(r.in() != *ptr_)
        {
            if(rel_)
            {
                T* old = *ptr_;
                *ptr_ = r.in();
                OBDuplicate(*ptr_);
                OBRelease(old);
            }
            else
            {
                *ptr_ = r.in();
                OBDuplicate(*ptr_);
            }
        }
        return *this;
    }
    ObjForSeq<T>& operator=(const ObjForSeq<T>& r)
    {
        if(*r.ptr_ != *ptr_)
        {
            if(rel_)
            {
                T* old = *ptr_;
                *ptr_ = *r.ptr_;
                OBDuplicate(*ptr_);
                OBRelease(old);
            }
            else
            {
                *ptr_ = *r.ptr_;
                OBDuplicate(*ptr_);
            }
        }
        return *this;
    }

    T* operator->() const { assert_nca(*ptr_ != 0, NCANullPtr); return *ptr_; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator T*() const { return *ptr_; }
#else
#   ifdef HAVE_NO_CONST_TYPE_CONVERSION_OVERLOAD
    operator T*&() const { return (T*&)*ptr_; }
#   else
    operator T*() const { return *ptr_; }
    operator T*&() { return *ptr_; }
#   endif
#endif

    T* in() const { return *ptr_; }
    T*& inout() { return *ptr_; }
    T*& out()
    {
        if(rel_)
        {
            T* old = *ptr_;
            *ptr_ = 0;
            OBRelease(old);
        }
        else
            *ptr_ = 0;
        return *ptr_;
    }
    T* _retn() { T* ret = *ptr_; *ptr_ = 0; return ret; }

    //
    // ORBacus-specific (the standard only defines this for _out types)
    //
    T*& ptr() { return *ptr_; }
};

template<class T>
inline
ObjVar<T>::ObjVar(const ObjForSeq<T>& r)
    : ptr_(r.in())
{
    OBDuplicate(ptr_);
}

template<class T>
inline ObjVar<T>&
ObjVar<T>::operator=(const ObjForSeq<T>& r)
{
    if(r.in() != ptr_)
    {
        T* old = ptr_;
        ptr_ = r.in();
        OBDuplicate(ptr_);
        OBRelease(old);
    }
    return *this;
}

// ----------------------------------------------------------------------
// T_out templates
// ----------------------------------------------------------------------

//
// T_out template for fixed-length general data types
//
/* Not needed */

//
// T_out template for variable-length general data types
//
template <class T>
class VarOut
{
    //
    // Assignment from T_var not allowed
    //
    void operator=(const VarVar<T>&) { }

    T*& ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    VarOut(T*& p)
        : ptr_(p)
    {
        ptr_ = 0;
    }

    VarOut(VarVar<T>& p)
        : ptr_(p.ptr_)
    {
        delete ptr_;
        ptr_ = 0;
    }

    VarOut(const VarOut<T>& p)
        : ptr_(p.ptr_)
    {
    }

    VarOut<T>& operator=(const VarOut<T>& p)
    {
        ptr_ = p.ptr_;
        return *this;
    }

    VarOut<T>& operator=(T* p)
    {
        ptr_ = p;
        return *this;
    }

    T* operator->() { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#else
    operator T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    operator T*&() { return ptr_; }
#endif

    T*& ptr() { return ptr_; }
};

//
// T_out template for sequence types
//
template<class T>
class SeqOut
{
    //
    // Assignment from T_var not allowed
    //
    void operator=(const SeqVar<T>&) { }

    T*& ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    SeqOut(T*& p)
        : ptr_(p)
    {
        ptr_ = 0;
    }

    SeqOut(SeqVar<T>& p)
        : ptr_(p.ptr_)
    {
        delete ptr_;
        ptr_ = 0;
    }

    SeqOut(const SeqOut<T>& p)
        : ptr_(p.ptr_)
    {
    }

    SeqOut<T>& operator=(const SeqOut<T>& p)
    {
        ptr_ = p.ptr_;
        return *this;
    }

    SeqOut<T>& operator=(T* p)
    {
        ptr_ = p;
        return *this;
    }

    T* operator->() { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }

#ifdef HAVE_NO_TYPENAME
    typedef T::SubType SubType;
    typedef T::ConstSubType ConstSubType;
#else
    typedef typename T::SubType SubType;
    typedef typename T::ConstSubType ConstSubType;
#endif

    SubType operator[](short idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](unsigned short idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](int idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](unsigned int idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](long idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }
    SubType operator[](unsigned long idx)
    { assert_nca(ptr_ != 0, NCANullPtr); return ptr_ -> operator[](idx); }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
#else
    operator T&() { assert_nca(ptr_ != 0, NCANullDeref); return *ptr_; }
    operator T*&() { return ptr_; }
#endif

    T*& ptr() { return ptr_; }
};

//
// T_out template for variable-length array types
//
template<class T_slice, class T, CORBA::ULong n>
class VarArrayOut
{
    //
    // Assignment from T_var not allowed
    //
    void operator=(const VarArrayVar<T_slice, T, n>&) { }
    T_slice*& ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    VarArrayOut(T_slice*& p)
        : ptr_(p)
    {
        ptr_ = 0;
    }

    VarArrayOut(VarArrayVar<T_slice, T, n>& p)
        : ptr_(p.ptr_)
    {
        delete[] ptr_;
        ptr_ = 0;
    }

    VarArrayOut(const VarArrayOut<T_slice, T, n>& p)
        : ptr_(p.ptr_)
    {
    }

    VarArrayOut<T_slice, T, n>& operator=(const VarArrayOut<T_slice, T, n>& p)
    {
        ptr_ = p.ptr_;
        return *this;
    }

    VarArrayOut<T_slice, T, n>& operator=(T_slice* p)
    {
        ptr_ = p;
        return *this;
    }

    T_slice& operator[](short idx) { return ptr_[idx]; }
    T_slice& operator[](unsigned short idx) { return ptr_[idx]; }
    T_slice& operator[](int idx) { return ptr_[idx]; }
    T_slice& operator[](unsigned int idx) { return ptr_[idx]; }
    T_slice& operator[](long idx) { return ptr_[idx]; }
    T_slice& operator[](unsigned long idx) { return ptr_[idx]; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator const T_slice*() { return ptr_; }
#else
    operator T_slice*&() { return ptr_; }
#endif

    T_slice*& ptr() { return ptr_; }
};

//
// T_out template for object reference data types
//
template <class T>
class ObjOut
{
    T*& ptr_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    ObjOut(T*& p)
        : ptr_(p)
    {
        ptr_ = 0;
    }

    ObjOut(ObjVar<T>& p)
        : ptr_(p.ptr_)
    {
        T* old = ptr_;
        ptr_ = 0;
        OBRelease(old);
    }

    ObjOut(const ObjOut<T>& p)
        : ptr_(p.ptr_)
    {
    }

    ObjOut<T>& operator=(const ObjOut<T>& p)
    {
        ptr_ = p.ptr_;
        return *this;
    }

    ObjOut<T>& operator=(const ObjVar<T>& p)
    {
        OBDuplicate(p);
        ptr_ = p.in();
        return *this;
    }

    ObjOut<T>& operator=(T* p)
    {
        ptr_ = p;
        return *this;
    }

    T* operator->() { assert_nca(ptr_ != 0, NCANullPtr); return ptr_; }

#ifdef OB_ONLY_IN_TYPE_CONVERSION
    operator T*() { return ptr_; }
#else
    operator T*&() { return ptr_; }
#endif

    T*& ptr() { return ptr_; }
};

// ----------------------------------------------------------------------
// Sequences
// ----------------------------------------------------------------------

//
// Template for fixed-length general unbounded sequence type
//
template<class T, class U>
class FixSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T* allocbuf(CORBA::ULong n);
    static void freebuf(T* p) { delete [] p; }

    FixSeq();
    FixSeq(CORBA::ULong);
    FixSeq(CORBA::ULong, CORBA::ULong, T*, CORBA::Boolean = false);
    FixSeq(const FixSeq<T, U>&);
    ~FixSeq() { if(rel_) freebuf(data_); }

    FixSeq<T, U>& operator=(const FixSeq<T, U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T& SubType;
    typedef const T& ConstSubType;

    T& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
    const T& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, T*,
                 CORBA::Boolean = false);
    T* get_buffer(CORBA::Boolean = false);
    const T* get_buffer() const { return data_; }
};

//
// Template for fixed-length general bounded sequence type
//
template<class T, CORBA::ULong max, class U>
class BndFixSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T* allocbuf(CORBA::ULong);
    static void freebuf(T* p) { delete [] p; }

    BndFixSeq();
    BndFixSeq(CORBA::ULong, T*, CORBA::Boolean = false);
    BndFixSeq(const BndFixSeq<T, max, U>&);
    ~BndFixSeq() { if(rel_) freebuf(data_); }

    BndFixSeq<T, max, U>& operator=(const BndFixSeq<T, max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T& SubType;
    typedef const T& ConstSubType;

    T& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
    const T& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, T*, CORBA::Boolean = false);
    T* get_buffer(CORBA::Boolean = false);
    const T* get_buffer() const { return data_; }
};

//
// Template for variable-length general unbounded sequence type
//
template<class T, class U>
class VarSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T* allocbuf(CORBA::ULong n);
    static void freebuf(T* p) { delete [] p; }

    VarSeq();
    VarSeq(CORBA::ULong);
    VarSeq(CORBA::ULong, CORBA::ULong, T*, CORBA::Boolean = false);
    VarSeq(const VarSeq<T, U>&);
    ~VarSeq() { if(rel_) freebuf(data_); }

    VarSeq<T, U>& operator=(const VarSeq<T, U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T& SubType;
    typedef const T& ConstSubType;

    T& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
    const T& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, T*, CORBA::Boolean = false);
    T* get_buffer(CORBA::Boolean = false);
    const T* get_buffer() const { return data_; }
};

//
// Template for variable-length general bounded sequence type
//
template<class T, CORBA::ULong max, class U>
class BndVarSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T* allocbuf(CORBA::ULong);
    static void freebuf(T* p) { delete [] p; }

    BndVarSeq();
    BndVarSeq(CORBA::ULong, T*, CORBA::Boolean = false);
    BndVarSeq(const BndVarSeq<T, max, U>&);
    ~BndVarSeq() { if(rel_) freebuf(data_); }

    BndVarSeq<T, max, U>& operator=(const BndVarSeq<T, max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T& SubType;
    typedef const T& ConstSubType;

    T& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
    const T& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, T*, CORBA::Boolean = false);
    T* get_buffer(CORBA::Boolean = false);
    const T* get_buffer() const { return data_; }
};

//
// Template for fixed-length array unbounded sequence type
//
template<class T_arr, class T, CORBA::ULong n, class U>
class FixArraySeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T_arr* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T_arr* allocbuf(CORBA::ULong);
    static void freebuf(T_arr*);

    FixArraySeq();
    FixArraySeq(CORBA::ULong);
    FixArraySeq(CORBA::ULong, CORBA::ULong, T_arr*, CORBA::Boolean = false);
    FixArraySeq(const FixArraySeq<T_arr, T, n, U>&);
    ~FixArraySeq() { if(rel_) freebuf(data_); }

    FixArraySeq<T_arr, T, n, U>&
    operator=(const FixArraySeq<T_arr, T, n, U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T_arr& SubType;
    typedef const T_arr& ConstSubType;

    T_arr& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#if defined(HAVE_VCPLUSPLUS_BUGS) && !defined (__BORLANDC__)
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange);
      return (const T_arr&)data_[idx]; }
#else
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#endif

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, T_arr*,
                 CORBA::Boolean = false);
    T_arr* get_buffer(CORBA::Boolean = false);
#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_arr* get_buffer() const { return (const T_arr*)data_; }
#else
    const T_arr* get_buffer() const { return data_; }
#endif
};

//
// Template for fixed-length array bounded sequence type
//
template<class T_arr, class T, CORBA::ULong n, CORBA::ULong max, class U>
class BndFixArraySeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T_arr* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T_arr* allocbuf(CORBA::ULong);
    static void freebuf(T_arr*);

    BndFixArraySeq();
    BndFixArraySeq(CORBA::ULong, T_arr*, CORBA::Boolean = false);
    BndFixArraySeq(const BndFixArraySeq<T_arr, T, n, max, U>&);
    ~BndFixArraySeq() { if(rel_) freebuf(data_); }

    BndFixArraySeq<T_arr, T, n, max, U>&
    operator=(const BndFixArraySeq<T_arr, T, n, max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T_arr& SubType;
    typedef const T_arr& ConstSubType;

    T_arr& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#if defined (HAVE_VCPLUSPLUS_BUGS) && !defined(__BORLANDC__)
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange);
      return (const T_arr&)data_[idx]; }
#else
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#endif

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, T_arr*, CORBA::Boolean = false);
    T_arr* get_buffer(CORBA::Boolean = false);
#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_arr* get_buffer() const { return (const T_arr*)data_; }
#else
    const T_arr* get_buffer() const { return data_; }
#endif
};

//
// Template for variable-length array unbounded sequence type
//
template<class T_arr, class T, CORBA::ULong n, class U>
class VarArraySeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T_arr* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T_arr* allocbuf(CORBA::ULong);
    static void freebuf(T_arr*);

    VarArraySeq();
    VarArraySeq(CORBA::ULong);
    VarArraySeq(CORBA::ULong, CORBA::ULong, T_arr*, CORBA::Boolean = false);
    VarArraySeq(const VarArraySeq<T_arr, T, n, U>&);
    ~VarArraySeq() { if(rel_) freebuf(data_); }

    VarArraySeq<T_arr, T, n, U>&
    operator=(const VarArraySeq<T_arr, T, n, U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T_arr& SubType;
    typedef const T_arr& ConstSubType;

    T_arr& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#if defined(HAVE_VCPLUSPLUS_BUGS) && !defined(__BORLANDC__)
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange);
      return (const T_arr&)data_[idx]; }
#else
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#endif

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, T_arr*,
                 CORBA::Boolean = false);
    T_arr* get_buffer(CORBA::Boolean = false);
#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_arr* get_buffer() const { return (const T_arr*)data_; }
#else
    const T_arr* get_buffer() const { return data_; }
#endif
};

//
// Template for variable-length array bounded sequence type
//
template<class T_arr, class T, CORBA::ULong n, CORBA::ULong max, class U>
class BndVarArraySeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T_arr* data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T_arr* allocbuf(CORBA::ULong);
    static void freebuf(T_arr*);

    BndVarArraySeq();
    BndVarArraySeq(CORBA::ULong, T_arr*, CORBA::Boolean = false);
    BndVarArraySeq(const BndVarArraySeq<T_arr, T, n, max, U>&);
    ~BndVarArraySeq() { if(rel_) freebuf(data_); }

    BndVarArraySeq<T_arr, T, n, max, U>&
    operator=(const BndVarArraySeq<T_arr, T, n, max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef T_arr& SubType;
    typedef const T_arr& ConstSubType;

    T_arr& operator[](CORBA::ULong idx)
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#if defined(HAVE_VCPLUSPLUS_BUGS)  && !defined(__BORLANDC__)
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange);
      return (const T_arr&)data_[idx]; }
#else
    const T_arr& operator[](CORBA::ULong idx) const
    { assert_nca(idx < len_, NCASeqRange); return data_[idx]; }
#endif

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, T_arr*, CORBA::Boolean = false);
    T_arr* get_buffer(CORBA::Boolean = false);
#ifdef HAVE_VCPLUSPLUS_BUGS
    const T_arr* get_buffer() const { return (const T_arr*)data_; }
#else
    const T_arr* get_buffer() const { return data_; }
#endif
};

//
// Template for unbounded object reference sequence type
//
template<class T, class U>
class ObjSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T** data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T** allocbuf(CORBA::ULong);
    static void freebuf(T**);

    ObjSeq();
    ObjSeq(CORBA::ULong);
    ObjSeq(CORBA::ULong, CORBA::ULong, T**, CORBA::Boolean = false);
    ObjSeq(const ObjSeq<T, U>&);
    ~ObjSeq() { if(rel_) freebuf(data_); }

    ObjSeq<T, U>& operator=(const ObjSeq<T, U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef ObjForSeq<T> SubType;
    typedef ObjForSeq<T> ConstSubType;

    //
    // COMPILERFIX: This must be changed - I need a const and a non-const
    // version of this operator. But the problem is that the following
    // code does not work with all compilers (for example not with SGI
    // CC 7.1):
    //
    // const ObjForSeq<T> operator[](CORBA::ULong idx) const
    //
    ObjForSeq<T> operator[](CORBA::ULong idx) const
    {
        assert_nca(idx < len_, NCASeqRange);
        return ObjForSeq<T>(&data_[idx], rel_);
    }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, T**,
                 CORBA::Boolean = false);
    T** get_buffer(CORBA::Boolean = false);
    T* const * get_buffer() const { return data_; }
};

//
// Template for bounded object reference sequence type
//
template<class T, CORBA::ULong max, class U>
class BndObjSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    T** data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static T** allocbuf(CORBA::ULong);
    static void freebuf(T**);

    BndObjSeq();
    BndObjSeq(CORBA::ULong, T**, CORBA::Boolean = false);
    BndObjSeq(const BndObjSeq<T, max, U>&);
    ~BndObjSeq() { if(rel_) freebuf(data_); }

    BndObjSeq<T, max, U>&
    operator=(const BndObjSeq<T, max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef ObjForSeq<T> SubType;
    typedef ObjForSeq<T> ConstSubType;

    //
    // TODO: See the comments in ObjSeq
    //
    ObjForSeq<T> operator[](CORBA::ULong idx) const
    {
        assert_nca(idx < len_, NCASeqRange);
        return ObjForSeq<T>(&data_[idx], rel_);
    }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, T**,
                 CORBA::Boolean = false);
    T** get_buffer(CORBA::Boolean = false);
    T* const * get_buffer() const { return data_; }
};

//
// Unbounded string sequence type
//
template<class U>
class StrSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    char** data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static char** allocbuf(CORBA::ULong n)
    { return OB::StrSeqAllocbuf(n); }
    static void freebuf(char** p)
    { OB::StrSeqFreebuf(p); }

    StrSeq();
    StrSeq(CORBA::ULong);
    StrSeq(CORBA::ULong, CORBA::ULong, char**, CORBA::Boolean = false);
    StrSeq(const StrSeq<U>&);
    ~StrSeq() { if(rel_) freebuf(data_); }

    StrSeq& operator=(const StrSeq<U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef StrForSeq SubType;
    typedef const char* ConstSubType;

    StrForSeq operator[](CORBA::ULong idx)
    {
        assert_nca(idx < len_, NCASeqRange);
        return StrForSeq(&data_[idx], rel_);
    }

    const char* operator[](CORBA::ULong idx) const
    {
        assert_nca(idx < len_, NCASeqRange);
        return data_[idx];
    }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, char**,
                 CORBA::Boolean = false);
    char** get_buffer(CORBA::Boolean = false);
    const char* const * get_buffer() const { return data_; }
};

//
// Template for bounded string sequence type
//
template<CORBA::ULong max, class U>
class BndStrSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    char** data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static char** allocbuf(CORBA::ULong);
    static void freebuf(char** p)
    { OB::StrSeqFreebuf(p); }

    BndStrSeq();
    BndStrSeq(CORBA::ULong, char**, CORBA::Boolean = false);
    BndStrSeq(const BndStrSeq<max, U>&);
    ~BndStrSeq() { if(rel_) freebuf(data_); }

    BndStrSeq<max, U>& operator=(const BndStrSeq<max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef StrForSeq SubType;
    typedef const char* ConstSubType;

    StrForSeq operator[](CORBA::ULong idx)
    {
        assert_nca(idx < len_, NCASeqRange);
        return StrForSeq(&data_[idx], rel_);
    }

    const char* operator[](CORBA::ULong idx) const
    {
        assert_nca(idx < len_, NCASeqRange);
        return data_[idx];
    }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, char**,
                 CORBA::Boolean = false);
    char** get_buffer(CORBA::Boolean = false);
    const char* const * get_buffer() const { return data_; }
};

//
// Unbounded wide string sequence type
//
template<class U>
class WStrSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong max_;
    CORBA::ULong len_;
    CORBA::Boolean rel_;
    wchar_t** data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static wchar_t** allocbuf(CORBA::ULong n)
    { return OB::WStrSeqAllocbuf(n); }
    static void freebuf(wchar_t** p)
    { OB::WStrSeqFreebuf(p); }

    WStrSeq();
    WStrSeq(CORBA::ULong);
    WStrSeq(CORBA::ULong, CORBA::ULong, wchar_t**, CORBA::Boolean = false);
    WStrSeq(const WStrSeq<U>&);
    ~WStrSeq() { if(rel_) freebuf(data_); }

    WStrSeq& operator=(const WStrSeq<U>&);

    CORBA::ULong maximum() const { return max_; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef WStrForSeq SubType;
    typedef const wchar_t* ConstSubType;

    WStrForSeq operator[](CORBA::ULong idx)
    {
        assert_nca(idx < len_, NCASeqRange);
        return WStrForSeq(&data_[idx], rel_);
    }

    const wchar_t* operator[](CORBA::ULong idx) const
    {
        assert_nca(idx < len_, NCASeqRange);
        return data_[idx];
    }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, CORBA::ULong, wchar_t**,
                 CORBA::Boolean = false);
    wchar_t** get_buffer(CORBA::Boolean = false);
    const wchar_t* const * get_buffer() const { return data_; }
};

//
// Template for bounded wide string sequence type
//
template<CORBA::ULong max, class U>
class BndWStrSeq
{
    //
    // The U template parameter is only used to be able to instantiate
    // two templates that are equivalent, except for different U
    // types.
    //
    typedef U Unique;

    CORBA::ULong len_;
    CORBA::Boolean rel_;
    wchar_t** data_;

public:

    //
    // Standard IDL to C++ Mapping
    //
    static wchar_t** allocbuf(CORBA::ULong);
    static void freebuf(wchar_t** p)
    { OB::WStrSeqFreebuf(p); }

    BndWStrSeq();
    BndWStrSeq(CORBA::ULong, wchar_t**, CORBA::Boolean = false);
    BndWStrSeq(const BndWStrSeq<max, U>&);
    ~BndWStrSeq() { if(rel_) freebuf(data_); }

    BndWStrSeq<max, U>& operator=(const BndWStrSeq<max, U>&);

    CORBA::ULong maximum() const { return max; }

    void length(CORBA::ULong);
    CORBA::ULong length() const { return len_; }

    typedef WStrForSeq SubType;
    typedef const wchar_t* ConstSubType;

    WStrForSeq operator[](CORBA::ULong idx)
    {
        assert_nca(idx < len_, NCASeqRange);
        return WStrForSeq(&data_[idx], rel_);
    }

    const wchar_t* operator[](CORBA::ULong idx) const
    {
        assert_nca(idx < len_, NCASeqRange);
        return data_[idx];
    }

    CORBA::Boolean release() const { return rel_; }
    void replace(CORBA::ULong, wchar_t**,
                 CORBA::Boolean = false);
    wchar_t** get_buffer(CORBA::Boolean = false);
    const wchar_t* const * get_buffer() const { return data_; }
};

// ----------------------------------------------------------------------
// Constructed type info class (for use with the any type)
// ----------------------------------------------------------------------

class ConstructedInfo
{
    //
    // Hide copy-constructor and assignment operator
    //
    ConstructedInfo(const ConstructedInfo&);
    void operator=(const ConstructedInfo&);
    void operator==(const ConstructedInfo&);

public:

    ConstructedInfo() { };
    virtual ~ConstructedInfo() { };

    //
    // void* memory handling
    //
    virtual void free(void*) const = 0;
    virtual void* dup(const void*) const = 0;

    //
    // CDR
    //
    virtual void marshal(const void*, OutputStreamImpl*) const = 0;
    virtual void unmarshal(void*, InputStreamImpl*) const = 0;
};

// ----------------------------------------------------------------------
// Constructed type info class (for use with the any type)
// ----------------------------------------------------------------------

//
// This is for all types that use new/delete
//
template<class T>
class Info : public ConstructedInfo
{
public:

    Info() { };

    virtual void free(void* p) const
    { delete (T*)p; }

    virtual void* dup(const void* p) const
    { return new T(*(const T*)p); }

    virtual void marshal(const void* p, OutputStreamImpl* out) const
    { ((const T*)p) -> _OB_marshal(out); }

    virtual void unmarshal(void* p, InputStreamImpl* in) const
    { T::_OB_unmarshal(*(T*)p, in); }
};

} // End of namespace OB

//
// Include non-inline template operations
//
#if !defined(__TEMPINC__)
# include <OB/TemplateI.h>
#else
# pragma implementation("TemplateI.h")
#endif

#endif
