// balber_berdecoderoptions.h                                         -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BALBER_BERDECODEROPTIONS
#define INCLUDED_BALBER_BERDECODEROPTIONS

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

//@PURPOSE: Provide an attribute class for specifying BER decoding options.
//
//@CLASSES:
//  balber::BerDecoderOptions: options for decoding objects in BDE format
//
//@DESCRIPTION: Schema of options records for 'balber' codecs

#include <balscm_version.h>

#include <bdlat_attributeinfo.h>
#include <bdlat_typetraits.h>
#include <bdlat_valuetypefunctions.h>

#include <bsls_assert.h>

#include <bslx_instreamfunctions.h>
#include <bslx_outstreamfunctions.h>

#include <bdlb_printmethods.h>

#include <bsl_iosfwd.h>

namespace BloombergLP {
namespace balber {

                          // =======================
                          // class BerDecoderOptions
                          // =======================

class BerDecoderOptions {
    // BER decoding options

  private:
    int   d_maxDepth;            // maximum recursion depth
    int   d_traceLevel;          // trace (verbosity) level
    int   d_maxSequenceSize;     // maximum sequence size
    bool  d_skipUnknownElements; // if 'true', skip unknown elements
    bool  d_defaultEmptyStrings; // if 'true', decode empty strings as their
                                 // default values, if any

  public:
    // TYPES
    enum {
        k_NUM_ATTRIBUTES = 5  // the number of attributes in this class

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
      , NUM_ATTRIBUTES = k_NUM_ATTRIBUTES
#endif  // BDE_OMIT_INTERNAL_DEPRECATED
    };

    enum {
        e_ATTRIBUTE_INDEX_MAX_DEPTH             = 0
            // index for "MaxDepth" attribute
      , e_ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS = 1
            // index for "SkipUnknownElements" attribute
      , e_ATTRIBUTE_INDEX_TRACE_LEVEL           = 2
            // index for "TraceLevel" attribute
      , e_ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE     = 3
            // index for "MaxSequenceSize" attribute
      , e_ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS = 4
            // index for "DefaultEmptyStrings" attribute

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
      , ATTRIBUTE_INDEX_MAX_DEPTH             =
                                        e_ATTRIBUTE_INDEX_MAX_DEPTH
      , ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS =
                                        e_ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS
      , ATTRIBUTE_INDEX_TRACE_LEVEL           =
                                        e_ATTRIBUTE_INDEX_TRACE_LEVEL
      , ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE     =
                                        e_ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE
      , ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS =
                                        e_ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS
#endif  // BDE_OMIT_INTERNAL_DEPRECATED
    };

    enum {
        e_ATTRIBUTE_ID_MAX_DEPTH             = 0
            // id for 'MaxDepth' attribute
      , e_ATTRIBUTE_ID_SKIP_UNKNOWN_ELEMENTS = 1
            // id for 'SkipUnknownElements' attribute
      , e_ATTRIBUTE_ID_TRACE_LEVEL           = 2
            // id for 'TraceLevel' attribute
      , e_ATTRIBUTE_ID_MAX_SEQUENCE_SIZE     = 3
            // id for 'MaxSequenceSize' attribute
      , e_ATTRIBUTE_ID_DEFAULT_EMPTY_STRINGS = 4
            // id for 'DefaultEmptyStrnigs" attribute

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
      , ATTRIBUTE_ID_MAX_DEPTH             = e_ATTRIBUTE_ID_MAX_DEPTH
      , ATTRIBUTE_ID_SKIP_UNKNOWN_ELEMENTS =
                                           e_ATTRIBUTE_ID_SKIP_UNKNOWN_ELEMENTS
      , ATTRIBUTE_ID_TRACE_LEVEL           = e_ATTRIBUTE_ID_TRACE_LEVEL
      , ATTRIBUTE_ID_MAX_SEQUENCE_SIZE     = e_ATTRIBUTE_ID_MAX_SEQUENCE_SIZE
      , ATTRIBUTE_ID_DEFAULT_EMPTY_STRINGS =
                                           e_ATTRIBUTE_ID_DEFAULT_EMPTY_STRINGS
#endif  // BDE_OMIT_INTERNAL_DEPRECATED
    };

  public:
    // CONSTANTS
    static const char CLASS_NAME[];
        // the name of this class (i.e., "BerDecoderOptions")

    static const int DEFAULT_MAX_DEPTH;
        // default value of 'MaxDepth' attribute

    static const bool DEFAULT_SKIP_UNKNOWN_ELEMENTS;
        // default value of 'SkipUnknownElements' attribute

    static const int DEFAULT_TRACE_LEVEL;
        // default value of 'TraceLevel' attribute

    static const int DEFAULT_MAX_SEQUENCE_SIZE;
        // default value of 'MaxSequenceSize' attribute

    static const bool DEFAULT_DEFAULT_EMPTY_STRINGS;
        // default value of 'DefaultEmptyStrings' attribute

    static const bdlat_AttributeInfo ATTRIBUTE_INFO_ARRAY[];
        // attribute information for each attribute

  public:
    // CLASS METHODS
    static int maxSupportedBdexVersion(int versionSelector);
        // Return the maximum valid BDEX format version, as indicated by the
        // specified 'versionSelector', to be passed to the 'bdexStreamOut'
        // method.  Note that it is highly recommended that 'versionSelector'
        // be formatted as "YYYYMMDD", a date representation.  Also note that
        // 'versionSelector' should be a *compile*-time-chosen value that
        // selects a format version supported by both externalizer and
        // unexternalizer.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

    static int maxSupportedBdexVersion();
        // Return the most current BDEX streaming version number supported by
        // this class.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

#endif  // BDE_OMIT_INTERNAL_DEPRECATED

    static const bdlat_AttributeInfo *lookupAttributeInfo(int id);
        // Return attribute information for the attribute indicated by the
        // specified 'id' if the attribute exists, and 0 otherwise.

    static const bdlat_AttributeInfo *lookupAttributeInfo(
                                                    const char *name,
                                                    int         nameLength);
        // Return attribute information for the attribute indicated by the
        // specified 'name' of the specified 'nameLength' if the attribute
        // exists, and 0 otherwise.

    // CREATORS
    BerDecoderOptions();
        // Create an object of type 'BerDecoderOptions' having the default
        // value.

    //! BerDecoderOptions(const BerDecoderOptions& original) = default;
        // Create a 'BderDecoderOptons' object having the same value as the
        // specified 'original'.

    //! ~BerDecoderOptions() = default;
        // Destroy this object.

    // MANIPULATORS
    //! BerDecoderOptions& operator=(const BerDecoderOptions& rhs) = default;
        // Assign to this object the value of the specified 'rhs' object.

    template <class STREAM>
    STREAM& bdexStreamIn(STREAM& stream, int version);
        // Assign to this object the value read from the specified input
        // 'stream' using the specified 'version' format, and return a
        // reference to 'stream'.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'version' is not supported, this object
        // is unaltered and 'stream' is invalidated, but otherwise unmodified.
        // If 'version' is supported but 'stream' becomes invalid during this
        // operation, this object has an undefined, but valid, state.  Note
        // that no version is read from 'stream'.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    void reset();
        // Reset this object to the default value (i.e., its value upon default
        // construction).

    template<class MANIPULATOR>
    int manipulateAttributes(MANIPULATOR& manipulator);
        // Invoke the specified 'manipulator' sequentially on the address of
        // each (modifiable) attribute of this object, supplying 'manipulator'
        // with the corresponding attribute information structure until such
        // invocation returns a non-zero value.  Return the value from the last
        // invocation of 'manipulator' (i.e., the invocation that terminated
        // the sequence).

    template<class MANIPULATOR>
    int manipulateAttribute(MANIPULATOR& manipulator, int id);
        // Invoke the specified 'manipulator' on the address of the
        // (modifiable) attribute indicated by the specified 'id', supplying
        // 'manipulator' with the corresponding attribute information
        // structure.  Return the value returned from the invocation of
        // 'manipulator' if 'id' identifies an attribute of this class, and -1
        // otherwise.

    template<class MANIPULATOR>
    int manipulateAttribute(MANIPULATOR&  manipulator,
                            const char   *name,
                            int           nameLength);
        // Invoke the specified 'manipulator' on the address of the
        // (modifiable) attribute indicated by the specified 'name' of the
        // specified 'nameLength', supplying 'manipulator' with the
        // corresponding attribute information structure.  Return the value
        // returned from the invocation of 'manipulator' if 'name' identifies
        // an attribute of this class, and -1 otherwise.

    void setMaxDepth(int value);
        // Set the 'MaxDepth' attribute of this object to the specified
        // 'value'.

    void setSkipUnknownElements(bool value);
        // Set the 'SkipUnknownElements' attribute of this object to the
        // specified 'value'.

    void setTraceLevel(int value);
        // Set the 'TraceLevel' attribute of this object to the specified
        // 'value'.

    void setMaxSequenceSize(int value);
        // Set the 'MaxSequenceSize' attribute of this object to the specified
        // 'value'.

    void setDefaultEmptyStrings(bool value);
        // Set the 'DefaultEmptyStrings' attribute of this object to the
        // specified 'value'.

    // ACCESSORS
    bsl::ostream& print(bsl::ostream& stream,
                        int           level = 0,
                        int           spacesPerLevel = 4) const;
        // Format this object to the specified output 'stream' at the
        // optionally specified indentation 'level' and return a reference to
        // the modifiable 'stream'.  If 'level' is specified, optionally
        // specify 'spacesPerLevel', the number of spaces per indentation level
        // for this and all of its nested objects.  Each line is indented by
        // the absolute value of 'level * spacesPerLevel'.  If 'level' is
        // negative, suppress indentation of the first line.  If
        // 'spacesPerLevel' is negative, suppress line breaks and format the
        // entire output on one line.  If 'stream' is initially invalid, this
        // operation has no effect.  Note that a trailing newline is provided
        // in multiline mode only.

    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, int version) const;
        // Write the value of this object, using the specified 'version'
        // format, to the specified output 'stream', and return a reference to
        // 'stream'.  If 'stream' is initially invalid, this operation has no
        // effect.  If 'version' is not supported, 'stream' is invalidated, but
        // otherwise unmodified.  Note that 'version' is not written to
        // 'stream'.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    template<class ACCESSOR>
    int accessAttributes(ACCESSOR& accessor) const;
        // Invoke the specified 'accessor' sequentially on each
        // (non-modifiable) attribute of this object, supplying 'accessor' with
        // the corresponding attribute information structure until such
        // invocation returns a non-zero value.  Return the value from the last
        // invocation of 'accessor' (i.e., the invocation that terminated the
        // sequence).

    template<class ACCESSOR>
    int accessAttribute(ACCESSOR& accessor, int id) const;
        // Invoke the specified 'accessor' on the (non-modifiable) attribute of
        // this object indicated by the specified 'id', supplying 'accessor'
        // with the corresponding attribute information structure.  Return the
        // value returned from the invocation of 'accessor' if 'id' identifies
        // an attribute of this class, and -1 otherwise.

    template<class ACCESSOR>
    int accessAttribute(ACCESSOR&   accessor,
                        const char *name,
                        int         nameLength) const;
        // Invoke the specified 'accessor' on the (non-modifiable) attribute of
        // this object indicated by the specified 'name' of the specified
        // 'nameLength', supplying 'accessor' with the corresponding attribute
        // information structure.  Return the value returned from the
        // invocation of 'accessor' if 'name' identifies an attribute of this
        // class, and -1 otherwise.

    const int& maxDepth() const;
        // Return a reference to the non-modifiable "MaxDepth" attribute of
        // this object.

    const bool& skipUnknownElements() const;
        // Return a reference to the non-modifiable "SkipUnknownElements"
        // attribute of this object.

    const int& traceLevel() const;
        // Return a reference to the non-modifiable "TraceLevel" attribute of
        // this object.

    const int& maxSequenceSize() const;
        // Return a reference to the non-modifiable "MaxSequenceSize" attribute
        // of this object.

    const bool& defaultEmptyStrings() const;
        // Return a reference to the non-modifiable "DefaultEmptyStrings"
        // attribute of this object.
};

// FREE OPERATORS
inline
bool operator==(const BerDecoderOptions& lhs,
                const BerDecoderOptions& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' attribute objects have
    // the same value, and 'false' otherwise.  Two attribute objects have the
    // same value if each respective attribute has the same value.

inline
bool operator!=(const BerDecoderOptions& lhs,
                const BerDecoderOptions& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' attribute objects do not
    // have the same value, and 'false' otherwise.  Two attribute objects do
    // not have the same value if one or more respective attributes differ in
    // values.

inline
bsl::ostream& operator<<(bsl::ostream&            stream,
                         const BerDecoderOptions& rhs);
    // Format the specified 'rhs' to the specified output 'stream' and return a
    // reference providing modifiable access to 'stream'.

}  // close package namespace


// TRAITS
BDLAT_DECL_SEQUENCE_TRAITS(balber::BerDecoderOptions)

namespace balber {

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

                          // -----------------------
                          // class BerDecoderOptions
                          // -----------------------

// CLASS METHODS
inline
int BerDecoderOptions::maxSupportedBdexVersion(int /* versionSelector */)
{
    return 1;  // versions start at 1
}

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

inline
int BerDecoderOptions::maxSupportedBdexVersion()
{
    return maxSupportedBdexVersion(0);
}

#endif  // BDE_OMIT_INTERNAL_DEPRECATED

// CREATORS
inline
BerDecoderOptions::BerDecoderOptions()
: d_maxDepth(DEFAULT_MAX_DEPTH)
, d_traceLevel(DEFAULT_TRACE_LEVEL)
, d_maxSequenceSize(DEFAULT_MAX_SEQUENCE_SIZE)
, d_skipUnknownElements(DEFAULT_SKIP_UNKNOWN_ELEMENTS)
, d_defaultEmptyStrings(DEFAULT_DEFAULT_EMPTY_STRINGS)
{
}

// MANIPULATORS
template <class STREAM>
inline
STREAM& BerDecoderOptions::bdexStreamIn(STREAM& stream, int version)
{
    if (stream) {
        switch (version) {  // Switch on the schema version (starting with 1).
          case 1: {
            bslx::InStreamFunctions::bdexStreamIn(stream, d_maxDepth, 1);
            bslx::InStreamFunctions::bdexStreamIn(stream,
                                                  d_skipUnknownElements, 1);
            bslx::InStreamFunctions::bdexStreamIn(stream, d_traceLevel, 1);
            bslx::InStreamFunctions::bdexStreamIn(stream,
                                                  d_maxSequenceSize, 1);
            bslx::InStreamFunctions::bdexStreamIn(stream,
                                                  d_defaultEmptyStrings, 1);
          } break;
          default: {
            stream.invalidate();
          }
        }
    }
    return stream;
}

inline
void BerDecoderOptions::reset()
{
    d_maxDepth            = DEFAULT_MAX_DEPTH;
    d_traceLevel          = DEFAULT_TRACE_LEVEL;
    d_maxSequenceSize     = DEFAULT_MAX_SEQUENCE_SIZE;
    d_skipUnknownElements = DEFAULT_SKIP_UNKNOWN_ELEMENTS;
    d_defaultEmptyStrings = DEFAULT_DEFAULT_EMPTY_STRINGS;
}

template <class MANIPULATOR>
inline
int BerDecoderOptions::manipulateAttributes(MANIPULATOR& manipulator)
{
    int ret;

    ret = manipulator(&d_maxDepth,
                      ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_DEPTH]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = manipulator(
                &d_skipUnknownElements,
                ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = manipulator(&d_traceLevel,
                      ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_TRACE_LEVEL]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = manipulator(
                    &d_maxSequenceSize,
                    ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = manipulator(
                &d_defaultEmptyStrings,
                ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    return ret;
}

template <class MANIPULATOR>
inline
int BerDecoderOptions::manipulateAttribute(MANIPULATOR& manipulator, int id)
{
    enum { k_NOT_FOUND = -1 };

    switch (id) {
      case e_ATTRIBUTE_ID_MAX_DEPTH: {
        return manipulator(&d_maxDepth,
                           ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_DEPTH]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_SKIP_UNKNOWN_ELEMENTS: {
        return manipulator(
               &d_skipUnknownElements,
               ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_TRACE_LEVEL: {
        return manipulator(
                          &d_traceLevel,
                          ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_TRACE_LEVEL]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_MAX_SEQUENCE_SIZE: {
        return manipulator(
                    &d_maxSequenceSize,
                    ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_DEFAULT_EMPTY_STRINGS: {
        return manipulator(
               &d_defaultEmptyStrings,
               ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS]);
                                                                      // RETURN
      } break;
      default:
        return k_NOT_FOUND;
    }
}

template <class MANIPULATOR>
inline
int BerDecoderOptions::manipulateAttribute(MANIPULATOR&  manipulator,
                                           const char   *name,
                                           int           nameLength)
{
    enum { k_NOT_FOUND = -1 };

    const bdlat_AttributeInfo *attributeInfo = lookupAttributeInfo(name,
                                                                   nameLength);
    if (!attributeInfo) {
        return k_NOT_FOUND;                                           // RETURN
    }

    return manipulateAttribute(manipulator, attributeInfo->d_id);
}

inline
void BerDecoderOptions::setMaxDepth(int value)
{
    d_maxDepth = value;
}

inline
void BerDecoderOptions::setSkipUnknownElements(bool value)
{
    d_skipUnknownElements = value;
}

inline
void BerDecoderOptions::setTraceLevel(int value)
{
    d_traceLevel = value;
}

inline
void BerDecoderOptions::setMaxSequenceSize(int value)
{
    d_maxSequenceSize = value;
}

inline
void BerDecoderOptions::setDefaultEmptyStrings(bool value)
{
    d_defaultEmptyStrings = value;
}

// ACCESSORS
template <class STREAM>
inline
STREAM& BerDecoderOptions::bdexStreamOut(STREAM& stream,
                                         int     version) const
{
    switch (version) {
      case 1: {
        bslx::OutStreamFunctions::bdexStreamOut(stream, d_maxDepth, 1);
        bslx::OutStreamFunctions::bdexStreamOut(
            stream, d_skipUnknownElements, 1);
        bslx::OutStreamFunctions::bdexStreamOut(stream, d_traceLevel, 1);
        bslx::OutStreamFunctions::bdexStreamOut(stream, d_maxSequenceSize, 1);
        bslx::OutStreamFunctions::bdexStreamOut(
            stream, d_defaultEmptyStrings, 1);
      } break;
      default: {
        stream.invalidate();
      } break;
    }
    return stream;
}

template <class ACCESSOR>
inline
int BerDecoderOptions::accessAttributes(ACCESSOR& accessor) const
{
    int ret;

    ret = accessor(d_maxDepth,
                   ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_DEPTH]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = accessor(
                d_skipUnknownElements,
                ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = accessor(d_traceLevel,
                   ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_TRACE_LEVEL]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = accessor(d_maxSequenceSize,
                   ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    ret = accessor(
                d_defaultEmptyStrings,
                ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS]);
    if (ret) {
        return ret;                                                   // RETURN
    }

    return ret;
}

template <class ACCESSOR>
inline
int BerDecoderOptions::accessAttribute(ACCESSOR& accessor, int id) const
{
    enum { k_NOT_FOUND = -1 };

    switch (id) {
      case e_ATTRIBUTE_ID_MAX_DEPTH: {
        return accessor(d_maxDepth,
                        ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_DEPTH]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_SKIP_UNKNOWN_ELEMENTS: {
        return accessor(
                d_skipUnknownElements,
                ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_SKIP_UNKNOWN_ELEMENTS]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_TRACE_LEVEL: {
        return accessor(d_traceLevel,
                        ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_TRACE_LEVEL]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_MAX_SEQUENCE_SIZE: {
        return accessor(
                    d_maxSequenceSize,
                    ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_MAX_SEQUENCE_SIZE]);
                                                                      // RETURN
      } break;
      case e_ATTRIBUTE_ID_DEFAULT_EMPTY_STRINGS: {
        return accessor(
                d_defaultEmptyStrings,
                ATTRIBUTE_INFO_ARRAY[e_ATTRIBUTE_INDEX_DEFAULT_EMPTY_STRINGS]);
                                                                      // RETURN
      } break;
      default:
        return k_NOT_FOUND;
    }
}

template <class ACCESSOR>
inline
int BerDecoderOptions::accessAttribute(ACCESSOR&   accessor,
                                       const char *name,
                                       int         nameLength) const
{
    enum { k_NOT_FOUND = -1 };

    const bdlat_AttributeInfo *attributeInfo = lookupAttributeInfo(name,
                                                                   nameLength);
    if (!attributeInfo) {
       return k_NOT_FOUND;                                            // RETURN
    }

    return accessAttribute(accessor, attributeInfo->d_id);
}

inline
const int& BerDecoderOptions::maxDepth() const
{
    return d_maxDepth;
}

inline
const bool& BerDecoderOptions::skipUnknownElements() const
{
    return d_skipUnknownElements;
}

inline
const int& BerDecoderOptions::traceLevel() const
{
    return d_traceLevel;
}

inline
const int& BerDecoderOptions::maxSequenceSize() const
{
    return d_maxSequenceSize;
}

inline
const bool& BerDecoderOptions::defaultEmptyStrings() const
{
    return d_defaultEmptyStrings;
}

}  // close package namespace

// FREE FUNCTIONS
inline
bool balber::operator==(const BerDecoderOptions& lhs,
                        const BerDecoderOptions& rhs)
{
    return  lhs.maxDepth()            == rhs.maxDepth()
         && lhs.skipUnknownElements() == rhs.skipUnknownElements()
         && lhs.traceLevel()          == rhs.traceLevel()
         && lhs.maxSequenceSize()     == rhs.maxSequenceSize()
         && lhs.defaultEmptyStrings() == rhs.defaultEmptyStrings();
}

inline
bool balber::operator!=(const BerDecoderOptions& lhs,
                        const BerDecoderOptions& rhs)
{
    return  lhs.maxDepth()            != rhs.maxDepth()
         || lhs.skipUnknownElements() != rhs.skipUnknownElements()
         || lhs.traceLevel()          != rhs.traceLevel()
         || lhs.maxSequenceSize()     != rhs.maxSequenceSize()
         || lhs.defaultEmptyStrings() != rhs.defaultEmptyStrings();
}

inline
bsl::ostream& balber::operator<<(bsl::ostream&            stream,
                                 const BerDecoderOptions& rhs)
{
    return rhs.print(stream, 0, -1);
}

}  // close enterprise namespace
#endif

// ----------------------------------------------------------------------------
// Copyright 2015 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 ----------------------------------