// s_baltst_testchoice.h                                              -*-C++-*-
#ifndef INCLUDED_S_BALTST_TESTCHOICE
#define INCLUDED_S_BALTST_TESTCHOICE

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a test implementation of a `bdlat` "choice" type.
//
//@CLASSES:
//  s_baltst::TestChoice: test implementation of a `bdlat` "choice" type

#include <bdlb_variant.h>

#include <bdlat_choicefunctions.h>

#include <bslma_allocator.h>
#include <bslma_default.h>

#include <bslmf_integralconstant.h>
#include <bslmf_issame.h>

#include <bsls_assert.h>

#include <bslalg_constructorproxy.h>

#include <s_baltst_testnilvalue.h>
#include <s_baltst_testselection.h>

namespace BloombergLP {
namespace s_baltst {

                         // ==========================
                         // struct TestChoice_ImplUtil
                         // ==========================

struct TestChoice_ImplUtil {

    // CLASS METHODS
    template <class ACCESSOR>
    static int access(ACCESSOR&                  accessor,
                      const TestNilValue         selection,
                      const bdlat_SelectionInfo& selectionInfo);
    template <class ACCESSOR, class SELECTION>
    static int access(ACCESSOR&                  accessor,
                      const SELECTION&           selection,
                      const bdlat_SelectionInfo& selectionInfo);

    template <class MANIPULATOR>
    static int manipulate(MANIPULATOR&                manipulator,
                          TestNilValue               *selection,
                          const bdlat_SelectionInfo&  selectionInfo);
    template <class MANIPULATOR, class SELECTION>
    static int manipulate(MANIPULATOR&                manipulator,
                          SELECTION                  *selection,
                          const bdlat_SelectionInfo&  selectionInfo);
};


                              // ================
                              // class TestChoice
                              // ================

/// This in-core value-semantic class provides a basic implementation of the
/// concept defined by the `Choice` `bdlat` type category.  The template
/// parameters `TYPED_SELECTION_0`, `TYPED_SELECTION_1`, and
/// `TYPED_SELECTION_2` must all satisfy the following requirements:
/// * The type must have two member type definitions, `Type`, and
///   `Selection`.
/// * `Type` must meet the requirements of an in-core value-semantic type.
/// * `Type` must meet the requirements of exactly one of the `bdlat` value
///   categories.
/// * `Selection` must be a specialization of the `TestSelection` type.
/// Further, each `TestSelection` member type definition of a template
/// argument must return values for `TestSelection::id()` and
/// `TestSelection::name()` that are different from all others within this
/// `TestChoice` specialization.
///
/// Additionally, The `Type` of any template argument may be `TestNilValue`
/// if all `Type` member type definitions of subsequent template arguments
/// are also `TestNilValue`.
///
/// The `Type` and `Selection` member type definitions of the template
/// arguments define the type and `bdlat_SelectionInfo` of the selections of
/// the `bdlat` `Choice` implementation provided by this class.  A template
/// argument having a `TestNilValue` `Type` indicates that the corresponding
/// selection does not exist.
template <class TYPED_SELECTION_0 =
              TypedTestSelection<TestNilValue, TestSelection<0> >,
          class TYPED_SELECTION_1 =
              TypedTestSelection<TestNilValue, TestSelection<0> >,
          class TYPED_SELECTION_2 =
              TypedTestSelection<TestNilValue, TestSelection<0> > >
class TestChoice {

  public:
    // TYPES
    typedef typename TYPED_SELECTION_0::Selection Selection0;
    typedef typename TYPED_SELECTION_0::Type      Selection0Type;
    typedef typename TYPED_SELECTION_1::Selection Selection1;
    typedef typename TYPED_SELECTION_1::Type      Selection1Type;
    typedef typename TYPED_SELECTION_2::Selection Selection2;
    typedef typename TYPED_SELECTION_2::Type      Selection2Type;

  private:
    // PRIVATE TYPES
    typedef TestChoice_ImplUtil ImplUtil;
    typedef bdlb::Variant<Selection0Type, Selection1Type, Selection2Type>
        Value;

    // PRIVATE CLASS DATA
    enum {
        k_HAS_CHOICE_0 = !bslmf::IsSame<TestNilValue, Selection0Type>::value,
        k_HAS_CHOICE_1 = !bslmf::IsSame<TestNilValue, Selection1Type>::value,
        k_HAS_CHOICE_2 = !bslmf::IsSame<TestNilValue, Selection2Type>::value
    };

    // DATA
    bslalg::ConstructorProxy<Value> d_value;  // underlying value
    bslma::Allocator *d_allocator_p;  // memory supply (held, not owned)

  public:
    // CLASS METHODS
    static bool areEqual(const TestChoice& lhs, const TestChoice& rhs);

    // CREATORS
    TestChoice();

    explicit TestChoice(bslma::Allocator *basicAllocator);

    template <class VALUE>
    explicit TestChoice(const VALUE&      value,
                        bslma::Allocator *basicAllocator = 0);

    TestChoice(const TestChoice&  original,
               bslma::Allocator  *basicAllocator = 0);

    // MANIPULATORS
    TestChoice& operator=(const TestChoice& original);

    int makeSelection(int selectionId);

    int makeSelection(const char *selectionName, int selectionNameLength);

    template <class MANIPULATOR>
    int manipulateSelection(MANIPULATOR& manipulator);

    void reset();

    // ACCESSORS
    template <class ACCESSOR>
    int accessSelection(ACCESSOR& accessor) const;

    bool hasSelection(int selectionId) const;

    bool hasSelection(const char *selectionName,
                      int         selectionNameLength) const;

    const char *className() const;

    int selectionId() const;

    const Selection0Type& theSelection0() const;

    const Selection1Type& theSelection1() const;

    const Selection2Type& theSelection2() const;
};

// FREE OPERATORS
template <class V0, class V1, class V2>
bsl::ostream& operator<<(bsl::ostream&                 stream,
                         const TestChoice<V0, V1, V2>& choice);

template <class C0, class C1, class C2>
inline
bool operator==(const TestChoice<C0, C1, C2>& lhs,
                const TestChoice<C0, C1, C2>& rhs);

template <class C0, class C1, class C2>
inline
bool operator!=(const TestChoice<C0, C1, C2>& lhs,
                const TestChoice<C0, C1, C2>& rhs);

// TRAITS

/// Return a null-terminated string containing the exported name of the type
/// for the specified `object`.
template <class C0, class C1, class C2>
const char *bdlat_TypeName_className(const TestChoice<C0, C1, C2>& object);

/// Set the value of the specified `object` to the default for the selection
/// indicated by the specified `selectionId`.  Return 0 on success, and a
/// non-zero value otherwise.
template <class C0, class C1, class C2>
int bdlat_choiceMakeSelection(TestChoice<C0, C1, C2> *object, int selectionId);


/// Set the value of the specified `object` to be the default for the
/// selection indicated by the specified `selectionName` of the specified
/// `selectionNameLength`.  Return 0 on success, and a non-zero value
/// otherwise.
template <class C0, class C1, class C2>
int bdlat_choiceMakeSelection(TestChoice<C0, C1, C2> *object,
                              const char             *selectionName,
                              int                     selectionNameLength);

/// Invoke the specified `manipulator` on the address of the (modifiable)
/// selection of the specified `object`, supplying `manipulator` with the
/// corresponding selection information structure.  Return -1 if the
/// selection is undefined, and the value returned from the invocation of
/// `manipulator` otherwise.
template <class C0, class C1, class C2, class MANIPULATOR>
int bdlat_choiceManipulateSelection(TestChoice<C0, C1, C2> *object,
                                    MANIPULATOR&            manipulator);

/// Invoke the specified `accessor` on the (non-modifiable) selection of the
/// specified `object`, supplying `accessor` with the corresponding
/// selection information structure.  Return -1 if the selection is
/// undefined, and the value returned from the invocation of `accessor`
/// otherwise.
template <class C0, class C1, class C2, class ACCESSOR>
int bdlat_choiceAccessSelection(const TestChoice<C0, C1, C2>& object,
                                ACCESSOR&                     accessor);

template <class C0, class C1, class C2>
bool bdlat_choiceHasSelection(
                           const TestChoice<C0, C1, C2>&  object,
                           const char                    *selectionName,
                           int                            selectionNameLength);

template <class C0, class C1, class C2>
bool bdlat_choiceHasSelection(const TestChoice<C0, C1, C2>& object,
                              int                           selectionId);

/// Return the id of the current selection if the selection is defined, and
/// `k_UNDEFINED_SELECTION_ID` otherwise.
template <class C0, class C1, class C2>
int bdlat_choiceSelectionId(const TestChoice<C0, C1, C2>& object);

template <class C0, class C1, class C2>
int bdlat_valueTypeAssign(TestChoice<C0, C1, C2>        *lhs,
                          const TestChoice<C0, C1, C2>&  rhs);

template <class C0, class C1, class C2>
void bdlat_valueTypeReset(TestChoice<C0, C1, C2> *object);

}  // close package namespace

namespace bdlat_ChoiceFunctions {

template <class C0, class C1, class C2>
struct IsChoice<s_baltst::TestChoice<C0, C1, C2> > : public bsl::true_type {
};

}  // close namespace bdlat_ChoiceFunctions

namespace s_baltst {

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                         // --------------------------
                         // struct TestChoice_ImplUtil
                         // --------------------------

// CLASS METHODS
template <class ACCESSOR>
int TestChoice_ImplUtil::access(ACCESSOR&,
                                const TestNilValue,
                                const bdlat_SelectionInfo&)
{
    return 0;
}

template <class ACCESSOR, class SELECTION>
int TestChoice_ImplUtil::access(ACCESSOR&                  accessor,
                                const SELECTION&           selection,
                                const bdlat_SelectionInfo& selectionInfo)
{
    return accessor(selection, selectionInfo);
}

template <class MANIPULATOR>
int TestChoice_ImplUtil::manipulate(MANIPULATOR&,
                                    TestNilValue               *,
                                    const bdlat_SelectionInfo&)
{
    return 0;
}

template <class MANIPULATOR, class SELECTION>
int TestChoice_ImplUtil::manipulate(MANIPULATOR&                manipulator,
                                    SELECTION                  *selection,
                                    const bdlat_SelectionInfo&  selectionInfo)
{
    return manipulator(selection, selectionInfo);
}

                              // ----------------
                              // class TestChoice
                              // ----------------

// CLASS METHODS
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
bool TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    areEqual(const TestChoice& lhs, const TestChoice& rhs)
{
    return lhs.d_value.object() == rhs.d_value.object();
}

// CREATORS
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    TestChoice()
: d_value(Selection0Type(), bslma::Default::allocator())
, d_allocator_p(bslma::Default::allocator())
{
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    TestChoice(bslma::Allocator *basicAllocator)
: d_value(Selection0Type(), basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
template <class VALUE>
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    TestChoice(const VALUE& value, bslma::Allocator *basicAllocator)
: d_value(value, bslma::Default::allocator(basicAllocator))
, d_allocator_p(basicAllocator)
{
    BSLMF_ASSERT((bslmf::IsSame<Selection0Type, VALUE>::value ||
                  bslmf::IsSame<Selection1Type, VALUE>::value ||
                  bslmf::IsSame<Selection2Type, VALUE>::value));
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    TestChoice(const TestChoice& original, bslma::Allocator *basicAllocator)
: d_value(original.d_value.object(), basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
}

// MANIPULATORS
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>&
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
operator=(const TestChoice& original)
{
    d_value.object() = original.d_value.object();
    return *this;
}

/// Set the value of this object to the default for the selection indicated
/// by the specified `selectionId`.  Return 0 on success, and a non-zero
/// value otherwise.
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
int TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    makeSelection(int selectionId)
{
    switch (selectionId) {
      case 0: {
        if (!k_HAS_CHOICE_0) {
            return -1;
        }                                                             // RETURN

        d_value.object().template createInPlace<Selection0Type>();
        return 0;                                                     // RETURN
      } break;
      case 1: {
        if (!k_HAS_CHOICE_1) {
            return -1;                                                // RETURN
        }

        d_value.object().template createInPlace<Selection1Type>();
        return 0;                                                     // RETURN
      } break;
      case 2: {
        if (!k_HAS_CHOICE_2) {
            return -1;
        }                                                             // RETURN

        d_value.object().template createInPlace<Selection2Type>();
        return 0;                                                     // RETURN
      } break;
    }

    return -1;
}

/// Set the value of this object to the default for the selection indicated
/// by the specified `selectionName` of the specified `selectionNameLength`.
/// Return 0 on success, and a non-zero value otherwise.
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
int TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    makeSelection(const char *selectionName, int selectionNameLength)
{
    const bsl::string_view selection(selectionName, selectionNameLength);

    if (k_HAS_CHOICE_0 && Selection0::name() == selection) {
        d_value.object().template createInPlace<Selection0Type>();
        return 0;                                                     // RETURN
    }

    if (k_HAS_CHOICE_1 && Selection1::name() == selection) {
        d_value.object().template createInPlace<Selection1Type>();
        return 0;                                                     // RETURN
    }

    if (k_HAS_CHOICE_2 && Selection2::name() == selection) {
        d_value.object().template createInPlace<Selection2Type>();
        return 0;                                                     // RETURN
    }

    return -1;
}

/// Invoke the specified `manipulator` on the address of the (modifiable)
/// selection of this object, supplying `manipulator` with the corresponding
/// selection information structure.  Return -1 if the selection is
/// undefined, and the value returned from the invocation of `manipulator`
/// otherwise.
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
template <class MANIPULATOR>
int TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    manipulateSelection(MANIPULATOR& manipulator)
{
    switch (d_value.object().typeIndex()) {
      case 0: {
        return -1;                                                    // RETURN
      } break;
      case 1: {
        BSLS_ASSERT(k_HAS_CHOICE_0);
        BSLS_ASSERT(d_value.object().template is<Selection0Type>());
        return ImplUtil::manipulate(
            manipulator,
            &d_value.object().template the<Selection0Type>(),
            Selection0::selectionInfo());                             // RETURN
      } break;
      case 2: {
        BSLS_ASSERT(k_HAS_CHOICE_1);
        BSLS_ASSERT(d_value.object().template is<Selection1Type>());
        return ImplUtil::manipulate(
            manipulator,
            &d_value.object().template the<Selection1Type>(),
            Selection1::selectionInfo());                             // RETURN
      } break;
      case 3: {
        BSLS_ASSERT(k_HAS_CHOICE_2);
        BSLS_ASSERT(d_value.object().template is<Selection2Type>());
        return ImplUtil::manipulate(
            manipulator,
            &d_value.object().template the<Selection2Type>(),
            Selection2::selectionInfo());                             // RETURN
      } break;
    }

    return -1;
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
void TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    reset()
{
    d_value.object().template createInPlace<Selection0Type>();
}

// ACCESSORS

/// Invoke the specified `accessor` on the (non-modifiable) selection of the
/// this object, supplying `accessor` with the corresponding selection
/// information structure.  Return -1 if the selection is undefined, and the
/// value returned from the invocation of `accessor` otherwise.
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
template <class ACCESSOR>
int TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    accessSelection(ACCESSOR& accessor) const
{
    switch (d_value.object().typeIndex()) {
      case 0: {
        return -1;                                                    // RETURN
      } break;
      case 1: {
        BSLS_ASSERT(k_HAS_CHOICE_0);
        BSLS_ASSERT(d_value.object().template is<Selection0Type>());
        return ImplUtil::access(
            accessor,
            d_value.object().template the<Selection0Type>(),
            Selection0::selectionInfo());                             // RETURN
      } break;
      case 2: {
        BSLS_ASSERT(k_HAS_CHOICE_1);
        BSLS_ASSERT(d_value.object().template is<Selection1Type>());
        return ImplUtil::access(
            accessor,
            d_value.object().template the<Selection1Type>(),
            Selection1::selectionInfo());                             // RETURN
      } break;
      case 3: {
        BSLS_ASSERT(k_HAS_CHOICE_2);
        BSLS_ASSERT(d_value.object().template is<Selection2Type>());
        return ImplUtil::access(
            accessor,
            d_value.object().template the<Selection2Type>(),
            Selection2::selectionInfo());                             // RETURN
      } break;
    }

    return -1;
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
bool TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    hasSelection(int selectionId) const
{
    if (k_HAS_CHOICE_0 && Selection0::id() == selectionId) {
        return true;                                                  // RETURN
    }

    if (k_HAS_CHOICE_1 && Selection1::id() == selectionId) {
        return true;                                                  // RETURN
    }

    if (k_HAS_CHOICE_2 && Selection2::id() == selectionId) {
        return true;                                                  // RETURN
    }

    return false;
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
bool TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    hasSelection(const char *selectionName, int selectionNameLength) const
{
    const bsl::string_view selection(selectionName, selectionNameLength);

    if (k_HAS_CHOICE_0 && Selection0::name() == selection) {
        return true;                                                  // RETURN
    }

    if (k_HAS_CHOICE_1 && Selection1::name() == selection) {
        return true;                                                  // RETURN
    }

    if (k_HAS_CHOICE_2 && Selection2::name() == selection) {
        return true;                                                  // RETURN
    }

    return false;
}

/// Return a null-terminated string containing the exported name for this
/// type.
template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
const char *TestChoice<TYPED_SELECTION_0,
                       TYPED_SELECTION_1,
                       TYPED_SELECTION_2>::className() const
{
    return "MyChoice";
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
int TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    selectionId() const
{
    return d_value.object().typeIndex() - 1;
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
const typename TYPED_SELECTION_0::Type&
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    theSelection0() const
{
    BSLS_ASSERT(d_value.object().typeIndex() == 1);
    return d_value.object().template the<Selection0Type>();
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
const typename TYPED_SELECTION_1::Type&
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    theSelection1() const
{
    BSLS_ASSERT(d_value.object().typeIndex() == 2);
    return d_value.object().template the<Selection1Type>();
}

template <class TYPED_SELECTION_0,
          class TYPED_SELECTION_1,
          class TYPED_SELECTION_2>
const typename TYPED_SELECTION_2::Type&
TestChoice<TYPED_SELECTION_0, TYPED_SELECTION_1, TYPED_SELECTION_2>::
    theSelection2() const
{
    BSLS_ASSERT(d_value.object().typeIndex() == 3);
    return d_value.object().template the<Selection2Type>();
}

// FREE OPERATORS
template <class V0, class V1, class V2>
bsl::ostream& operator<<(bsl::ostream&                 stream,
                         const TestChoice<V0, V1, V2>& choice)
{
    typedef TestChoice<V0, V1, V2> Choice;

    stream << "[" << choice.className() << " ";
    switch (choice.selectionId()) {
      case 0: {
        stream << Choice::Selection0::name() << " = "
               << choice.theSelection0();
      } break;
      case 1: {
        stream << Choice::Selection1::name() << " = "
               << choice.theSelection1();
      } break;
      case 2: {
        stream << Choice::Selection2::name() << " = "
               << choice.theSelection2();
      } break;
    }

    return stream << "]";
}

template <class C0, class C1, class C2>
inline
bool operator==(const TestChoice<C0, C1, C2>& lhs,
                const TestChoice<C0, C1, C2>& rhs)
{
    return TestChoice<C0, C1, C2>::areEqual(lhs, rhs);
}

template <class C0, class C1, class C2>
inline
bool operator!=(const TestChoice<C0, C1, C2>& lhs,
                const TestChoice<C0, C1, C2>& rhs)
{
    return !TestChoice<C0, C1, C2>::areEqual(lhs, rhs);
}

// TRAITS
template <class C0, class C1, class C2>
const char *bdlat_TypeName_className(const TestChoice<C0, C1, C2>& object)
{
    return object.className();
}

template <class C0, class C1, class C2>
int bdlat_choiceMakeSelection(TestChoice<C0, C1, C2> *object, int selectionId)
{
    return object->makeSelection(selectionId);
}

template <class C0, class C1, class C2>
int bdlat_choiceMakeSelection(TestChoice<C0, C1, C2> *object,
                              const char             *selectionName,
                              int                     selectionNameLength)
{
    return object->makeSelection(selectionName, selectionNameLength);
}

template <class C0, class C1, class C2, class MANIPULATOR>
int bdlat_choiceManipulateSelection(TestChoice<C0, C1, C2> *object,
                                    MANIPULATOR&            manipulator)
{
    return object->manipulateSelection(manipulator);
}

template <class C0, class C1, class C2, class ACCESSOR>
int bdlat_choiceAccessSelection(const TestChoice<C0, C1, C2>& object,
                                ACCESSOR&                     accessor)
{
    return object.accessSelection(accessor);
}

template <class C0, class C1, class C2>
bool bdlat_choiceHasSelection(
                            const TestChoice<C0, C1, C2>&  object,
                            const char                    *selectionName,
                            int                            selectionNameLength)
{
    return object.hasSelection(selectionName, selectionNameLength);
}

template <class C0, class C1, class C2>
bool bdlat_choiceHasSelection(const TestChoice<C0, C1, C2>& object,
                              int                           selectionId)
{
    return object.hasSelection(selectionId);
}

template <class C0, class C1, class C2>
int bdlat_choiceSelectionId(const TestChoice<C0, C1, C2>& object)
{
    return object.selectionId();
}

template <class C0, class C1, class C2>
int bdlat_valueTypeAssign(TestChoice<C0, C1, C2>        *lhs,
                          const TestChoice<C0, C1, C2>&  rhs)
{
    *lhs = rhs;
    return 0;
}

template <class C0, class C1, class C2>
void bdlat_valueTypeReset(TestChoice<C0, C1, C2> *object)
{
    object->reset();
}



}  // close package namespace
}  // close enterprise namespace

#endif // INCLUDED_S_BALTST_TESTCHOICE

// ----------------------------------------------------------------------------
// Copyright 2021 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
