Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdlat_sequencefunctions
[Package bdlat]

Provide a namespace defining sequence functions. More...

Namespaces

namespace  bdlat_SequenceFunctions

Detailed Description

Outline
Purpose:
Provide a namespace defining sequence functions.
Classes:
bdlat_SequenceFunctions namespace for calling sequence functions
See also:
Component bdlat_attributeinfo
Description:
The bdlat_SequenceFunctions namespace provided in this component defines parameterized functions that expose "sequence" behavior for "sequence" types. See the bdlat package-level documentation for a full description of "sequence" types.
The functions in this namespace allow users to:
  • manipulate an attribute by attribute id or attribute name using a parameterized manipulator (manipulateAttribute),
  • manipulate all attributes sequentially using a parameterized manipulator (manipulateAttributes),
  • access an attribute by attribute id or attribute name using a parameterized accessor (accessAttribute), and
  • access all attributes sequentially using a parameterized accessor (accessAttributes).
Also, the meta-function IsSequence contains a compile-time constant VALUE that is non-zero if the parameterized TYPE exposes "sequence" behavior through the bdlat_SequenceFunctions namespace.
This component specializes all of these functions for types that have the bdlat_TypeTraitBasicSequence trait.
Types that do not have the bdlat_TypeTraitBasicSequence trait can be plugged into the bdlat framework. This is done by overloading the bdlat_sequence* functions inside the namespace of the plugged in type. For example, suppose there is a type called mine::MySequence. In order to plug this type into the bdlat framework as a "sequence", the following functions must be declared and implemented in the mine namespace:
  namespace mine {

  // MANIPULATORS
  template <typename MANIPULATOR>
  int bdlat_sequenceManipulateAttribute(
                                      MySequence   *object,
                                      MANIPULATOR&  manipulator,
                                      const char   *attributeName,
                                      int           attributeNameLength);
      // Invoke the specified 'manipulator' on the address of the
      // (modifiable) attribute indicated by the specified 'attributeName'
      // and 'attributeNameLength' of the specified 'object', supplying
      // 'manipulator' with the corresponding attribute information
      // structure.  Return non-zero value if the attribute is not found, and
      // the value returned from the invocation of 'manipulator' otherwise.

  template <typename MANIPULATOR>
  int bdlat_sequenceManipulateAttribute(MySequence   *object,
                                        MANIPULATOR&  manipulator,
                                        int           attributeId);
      // Invoke the specified 'manipulator' on the address of the
      // (modifiable) attribute indicated by the specified 'attributeId' of
      // the specified 'object', supplying 'manipulator' with the
      // corresponding attribute information structure.  Return non-zero
      // value if the attribute is not found, and the value returned from the
      // invocation of 'manipulator' otherwise.

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

  // ACCESSORS
  template <typename ACCESSOR>
  int bdlat_sequenceAccessAttribute(const MySequence&  object,
                                    ACCESSOR&          accessor,
                                    const char        *attributeName,
                                    int                attributeNameLength);
      // Invoke the specified 'accessor' on the (non-modifiable) attribute of
      // the specified 'object' indicated by the specified 'attributeName'
      // and 'attributeNameLength', supplying 'accessor' with the
      // corresponding attribute information structure.  Return non-zero
      // value if the attribute is not found, and the value returned from the
      // invocation of 'accessor' otherwise.

  template <typename ACCESSOR>
  int bdlat_sequenceAccessAttribute(const MySequence& object,
                                    ACCESSOR&         accessor,
                                    int               attributeId);
      // Invoke the specified 'accessor' on the attribute of the specified
      // 'object' with the given 'attributeId', supplying 'accessor' with the
      // corresponding attribute information structure.  Return non-zero if
      // the attribute is not found, and the value returned from the
      // invocation of 'accessor' otherwise.

  template <typename ACCESSOR>
  int bdlat_sequenceAccessAttributes(const MySequence& object,
                                     ACCESSOR&         accessor);
      // Invoke the specified 'accessor' sequentially on each attribute of
      // the specified '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).

  bool bdlat_sequenceHasAttribute(const MySequence&  object,
                                  const char        *attributeName,
                                  int                attributeNameLength);
      // Return true if the specified 'object' has an attribute with the
      // specified 'attributeName' of the specified 'attributeNameLength',
      // and false otherwise.

  bool bdlat_sequenceHasAttribute(const MySequence& object,
                                  int               attributeId);
      // Return true if the specified 'object' has an attribute with the
      // specified 'attributeId', and false otherwise.

  }  // close namespace 'mine'
Also, the IsSequence meta-function must be specialized for the mine::MySequence type in the bdlat_SequenceFunctions namespace.
An example of plugging in a user-defined sequence type into the bdlat framework is shown in the Usage section of this document.
Usage:
The following snippets of code illustrate the usage of this component. Suppose you had a struct that contains three members:
  namespace BloombergLP {

  namespace mine {

  struct MySequence {
      // This struct represents a sequence containing a 'string' member, an
      // 'int' member, and a 'float' member.

      // CONSTANTS
      enum {
          NAME_ATTRIBUTE_ID   = 1,
          AGE_ATTRIBUTE_ID    = 2,
          SALARY_ATTRIBUTE_ID = 3
      };

      // DATA MEMBERS
      bsl::string d_name;
      int         d_age;
      float       d_salary;
  };

  }  // close namespace mine
We can now make mine::MySequence expose "sequence" behavior by implementing the necessary bdlat_sequence* functions for MySequence inside the mine namespace. First, we should forward declare all the functions that we will implement inside the mine namespace:
  namespace mine {

  template <class MANIPULATOR>
  int bdlat_sequenceManipulateAttribute(MySequence   *object,
                                        MANIPULATOR&  manipulator,
                                        const char   *attributeName,
                                        int           attributeNameLength);
  template <class MANIPULATOR>
  int bdlat_sequenceManipulateAttribute(MySequence   *object,
                                        MANIPULATOR&  manipulator,
                                        int           attributeId);
  template <class MANIPULATOR>
  int bdlat_sequenceManipulateAttributes(MySequence   *object,
                                         MANIPULATOR&  manipulator);
  template <class ACCESSOR>
  int bdlat_sequenceAccessAttribute(const MySequence&  object,
                                    ACCESSOR&          accessor,
                                    const char        *attributeName,
                                    int                attributeNameLength);
  template <class ACCESSOR>
  int bdlat_sequenceAccessAttribute(const MySequence& object,
                                    ACCESSOR&         accessor,
                                    int               attributeId);
  template <class ACCESSOR>
  int bdlat_sequenceAccessAttributes(const MySequence& object,
                                     ACCESSOR&         accessor);
  bool bdlat_sequenceHasAttribute(const MySequence&  object,
                                  const char        *attributeName,
                                  int                attributeNameLength);
  bool bdlat_sequenceHasAttribute(const MySequence& object,
                                  int               attributeId);

  }  // close namespace mine
Now, we will implement these functions. Note that for this implementation, we will create a temporary bdlat_AttributeInfo object and pass it along when invoking the manipulator or accessor. See the bdlat_attributeinfo component-level documentation for more information. The implementation of the functions are as follows:
  template <class MANIPULATOR>
  int mine::bdlat_sequenceManipulateAttribute(
                                        MySequence   *object,
                                        MANIPULATOR&  manipulator,
                                        const char   *attributeName,
                                        int           attributeNameLength)
  {
      enum { NOT_FOUND = -1 };

      if (bdlb::String::areEqualCaseless("name",
                                         attributeName,
                                         attributeNameLength)) {
          return bdlat_sequenceManipulateAttribute(
                                              object,
                                              manipulator,
                                              MySequence::NAME_ATTRIBUTE_ID);
                                                                    // RETURN
      }

      if (bdlb::String::areEqualCaseless("age",
                                         attributeName,
                                         attributeNameLength)) {
          return bdlat_sequenceManipulateAttribute(
                                               object,
                                               manipulator,
                                               MySequence::AGE_ATTRIBUTE_ID);
                                                                    // RETURN
      }

      if (bdlb::String::areEqualCaseless("salary",
                                         attributeName,
                                         attributeNameLength)) {
          return bdlat_sequenceManipulateAttribute(
                                            object,
                                            manipulator,
                                            MySequence::SALARY_ATTRIBUTE_ID);
                                                                    // RETURN
      }

      return NOT_FOUND;
  }

  template <class MANIPULATOR>
  int mine::bdlat_sequenceManipulateAttribute(MySequence   *object,
                                              MANIPULATOR&  manipulator,
                                              int           attributeId)
  {
      enum { NOT_FOUND = -1 };

      switch (attributeId) {
        case MySequence::NAME_ATTRIBUTE_ID: {
          bdlat_AttributeInfo info;

          info.annotation()     = "Name of employee";
          info.formattingMode() = bdlat_FormattingMode::e_DEFAULT;
          info.id()             = MySequence::NAME_ATTRIBUTE_ID;
          info.name()           = "name";
          info.nameLength()     = 4;

          return manipulator(&object->d_name, info);                // RETURN
        }
        case MySequence::AGE_ATTRIBUTE_ID: {
          bdlat_AttributeInfo info;

          info.annotation()     = "Age of employee";
          info.formattingMode() = bdlat_FormattingMode::e_DEFAULT;
          info.id()             = MySequence::AGE_ATTRIBUTE_ID;
          info.name()           = "age";
          info.nameLength()     = 3;

          return manipulator(&object->d_age, info);                 // RETURN
        }
        case MySequence::SALARY_ATTRIBUTE_ID: {
          bdlat_AttributeInfo info;

          info.annotation()     = "Salary of employee";
          info.formattingMode() = bdlat_FormattingMode::e_DEFAULT;
          info.id()             = MySequence::SALARY_ATTRIBUTE_ID;
          info.name()           = "salary";
          info.nameLength()     = 6;

          return manipulator(&object->d_salary, info);              // RETURN
        }
        default: {
          return NOT_FOUND;                                         // RETURN
        }
      }
  }

  template <class MANIPULATOR>
  int mine::bdlat_sequenceManipulateAttributes(MySequence   *object,
                                               MANIPULATOR&  manipulator)
  {
      int retVal;

      retVal = bdlat_sequenceManipulateAttribute(
                                              object,
                                              manipulator,
                                              MySequence::NAME_ATTRIBUTE_ID);

      if (0 != retVal) {
          return retVal;                                            // RETURN
      }

      retVal = bdlat_sequenceManipulateAttribute(
                                               object,
                                               manipulator,
                                               MySequence::AGE_ATTRIBUTE_ID);

      if (0 != retVal) {
          return retVal;                                            // RETURN
      }

      retVal = bdlat_sequenceManipulateAttribute(
                                            object,
                                            manipulator,
                                            MySequence::SALARY_ATTRIBUTE_ID);

      return retVal;
  }

  // ACCESSORS

  template <class ACCESSOR>
  int mine::bdlat_sequenceAccessAttribute(
                                      const MySequence&  object,
                                      ACCESSOR&          accessor,
                                      const char        *attributeName,
                                      int                attributeNameLength)
  {
      enum { NOT_FOUND = -1 };

      if (bdlb::String::areEqualCaseless("name",
                                         attributeName,
                                         attributeNameLength)) {
          return bdlat_sequenceAccessAttribute(
                                              object,
                                              accessor,
                                              MySequence::NAME_ATTRIBUTE_ID);
                                                                    // RETURN
      }

      if (bdlb::String::areEqualCaseless("age",
                                         attributeName,
                                         attributeNameLength)) {
          return bdlat_sequenceAccessAttribute(object,
                                               accessor,
                                               MySequence::AGE_ATTRIBUTE_ID);
                                                                    // RETURN
      }

      if (bdlb::String::areEqualCaseless("salary",
                                         attributeName,
                                         attributeNameLength)) {
          return bdlat_sequenceAccessAttribute(
                                            object,
                                            accessor,
                                            MySequence::SALARY_ATTRIBUTE_ID);
                                                                    // RETURN
      }

      return NOT_FOUND;
  }

  template <class ACCESSOR>
  int mine::bdlat_sequenceAccessAttribute(const MySequence& object,
                                          ACCESSOR&         accessor,
                                          int               attributeId)
  {
      enum { NOT_FOUND = -1 };

      switch (attributeId) {
        case MySequence::NAME_ATTRIBUTE_ID: {
          bdlat_AttributeInfo info;

          info.annotation()     = "Name of employee";
          info.formattingMode() = bdlat_FormattingMode::e_DEFAULT;
          info.id()             = MySequence::NAME_ATTRIBUTE_ID;
          info.name()           = "name";
          info.nameLength()     = 4;

          return accessor(object.d_name, info);                     // RETURN
        }
        case MySequence::AGE_ATTRIBUTE_ID: {
          bdlat_AttributeInfo info;

          info.annotation()     = "Age of employee";
          info.formattingMode() = bdlat_FormattingMode::e_DEFAULT;
          info.id()             = MySequence::AGE_ATTRIBUTE_ID;
          info.name()           = "age";
          info.nameLength()     = 3;

          return accessor(object.d_age, info);                      // RETURN
        }
        case MySequence::SALARY_ATTRIBUTE_ID: {
          bdlat_AttributeInfo info;

          info.annotation()     = "Salary of employee";
          info.formattingMode() = bdlat_FormattingMode::e_DEFAULT;
          info.id()             = MySequence::SALARY_ATTRIBUTE_ID;
          info.name()           = "salary";
          info.nameLength()     = 6;

          return accessor(object.d_salary, info);                   // RETURN
        }
        default: {
        return NOT_FOUND;                                           // RETURN
        }
      }
  }

  template <class ACCESSOR>
  int mine::bdlat_sequenceAccessAttributes(const MySequence& object,
                                           ACCESSOR&         accessor)
  {
      int retVal;

      retVal = bdlat_sequenceAccessAttribute(object,
                                             accessor,
                                             MySequence::NAME_ATTRIBUTE_ID);

      if (0 != retVal) {
      return retVal;                                                // RETURN
      }

      retVal = bdlat_sequenceAccessAttribute(object,
                                             accessor,
                                             MySequence::AGE_ATTRIBUTE_ID);

      if (0 != retVal) {
          return retVal;                                            // RETURN
      }

      retVal = bdlat_sequenceAccessAttribute(
                                            object,
                                            accessor,
                                            MySequence::SALARY_ATTRIBUTE_ID);

      return retVal;
  }

  bool mine::bdlat_sequenceHasAttribute(
                                      const MySequence&  ,
                                      const char        *attributeName,
                                      int                attributeNameLength)
  {
      return bdlb::String::areEqualCaseless("name",
                                            attributeName,
                                            attributeNameLength)
          || bdlb::String::areEqualCaseless("age",
                                            attributeName,
                                            attributeNameLength)
          || bdlb::String::areEqualCaseless("salary",
                                            attributeName,
                                            attributeNameLength);
  }

  bool mine::bdlat_sequenceHasAttribute(const MySequence& , int attributeId)
  {
      return MySequence::NAME_ATTRIBUTE_ID   == attributeId
          || MySequence::AGE_ATTRIBUTE_ID    == attributeId
          || MySequence::SALARY_ATTRIBUTE_ID == attributeId;
  }
Finally, we need to specialize the IsSequence meta-function in the bdlat_SequenceFunctions namespace for the mine::MySequence type. This makes the bdlat infrastructure recognize mine::MySequence as a sequence abstraction:
  namespace bdlat_SequenceFunctions {

  template <>
  struct IsSequence<mine::MySequence> {
      enum { VALUE = 1 };
  };

  }  // close namespace bdlat_SequenceFunctions
  }  // close enterprise namespace
The bdlat infrastructure (and any component that uses this infrastructure) will now recognize mine::MySequence as a "sequence" type. For example, suppose we have the following XML data:
  <?xml version='1.0' encoding='UTF-8' ?>
  <MySequence>
      <name>John Doe</name>
      <age>29</age>
      <salary>12345.00</salary>
  </MySequence>
Using the balxml_decoder component, we can now load this XML data into a mine::MySequence object:
  #include <balxml_decoder.h>

  void decodeMySequenceFromXML(bsl::istream& inputData)
  {
      using namespace BloombergLP;

      mine::MySequence object;

      balxml::DecoderOptions options;
      balxml::MiniReader     reader;
      balxml::ErrorInfo      errInfo;

      balxml::Decoder decoder(&options, &reader, &errInfo);
      int result = decoder.decode(inputData, &object);

      assert(0          == result);
      assert("John Doe" == object.d_name);
      assert(29         == object.d_age);
      assert(12345.00   == object.d_salary);
  }
Note that the bdlat framework can be used for functionality other than encoding/decoding into XML. When mine::MySequence is plugged into the framework, then it will be automatically usable within the framework. For example, the following snippets of code will print out all the attributes of a sequence object:
  struct PrintAttribute {
      // Print each visited object to the bound 'd_stream_p' object.

      // DATA MEMBERS
      bsl::ostream *d_stream_p;

      template <class TYPE, class INFO>
      int operator()(const TYPE& object, const INFO& info)
      {
          (*d_stream_p) << info.name() << ": " << object << bsl::endl;
          return 0;
      }
  };

  template <class TYPE>
  void printSequenceAttributes(bsl::ostream& stream, const TYPE& object)
  {
      PrintAttribute accessor;
      accessor.d_stream_p = &stream;

      bdlat_SequenceFunctions::accessAttributes(object, accessor);
  }
Now we have a generic function that takes an output stream and a sequence object, and prints out each attribute with its name and value. We can use this generic function as follows:
  void printMySequence(bsl::ostream& stream)
  {
      mine::MySequence object;

      object.d_name   = "John Doe";
      object.d_age    = 25;
      object.d_salary = 12345.00;

      stream << bsl::fixed << bsl::setprecision(2);

      printSequenceAttributes(stream, object);
  }
The function above will print the following to provided stream:
  name: John Doe
  age: 25
  salary: 12345.00