Quick Links:

bal | bbl | bdl | bsl

Classes | Namespaces

Component bdlat_customizedtypefunctions
[Package bdlat]

Provide a namespace defining customized type functions. More...

Classes

struct  bdlat_CustomizedTypeFunctions_Imp

Namespaces

namespace  bdlat_CustomizedTypeFunctions

Detailed Description

Outline
Purpose:
Provide a namespace defining customized type functions.
Classes:
bdlat_CustomizedTypeFunctions namespace for customized type functions
See also:
Description:
The bdlat_CustomizedTypeFunctions namespace provided in this component defines parameterized functions that expose "customized type" behavior for "customized type" types. See the package-level documentation for a full description of "customized type" types. The functions in this namespace allow users to:
      o convert from base type to customized type ('convertFromBaseType').
      o convert from customized type to base type ('convertToBaseType').
Also, the meta-function IsCustomizedType contains a compile-time constant VALUE that is non-zero if the parameterized TYPE exposes "customized type" behavior through the bdlat_CustomizedTypeFunctions namespace.
The BaseType meta-function contains a typedef Type that specifies the base type of the value for the parameterized "customized type" type.
This component specializes all of these functions for types that have the bdlat_TypeTraitBasicCustomizedType trait.
Types that do not have the bdlat_TypeTraitBasicCustomizedType trait can be plugged into the bdlat framework. This is done by overloading the bdlat_choice* functions inside the namespace of the plugged in type. For example, suppose there is a type called mine::Cusip (defined in the example below). In order to plug this type into the bdlat framework as a "CustomizedType", the following functions must be declared and implemented in the mine namespace:
      // MANIPULATORS
      template <typename TYPE, typename BASE_TYPE>
      int bdlat_customizedTypeConvertFromBaseType(TYPE             *object,
                                                  const BASE_TYPE&  value);
          // Convert from the specified 'value' to the specified customized
          // 'object'.  Return 0 if successful and non-zero otherwise.

      // ACCESSORS
      template <typename TYPE>
      const typename BaseType<TYPE>::Type&
      bdlat_customizedTypeConvertToBaseType(const TYPE& object);
          // Load into the specified 'result' the value of the specified
          // 'object'.
Also, the IsCustomizedType meta-function must be specialized for the mine::Cusip type in the bdlat_CustomizedTypeFunctions namespace.
Usage:
The following snippets of code illustrate the usage of this component. Suppose we have a customized type called Cusip, holding an object of type bsl::string with a restriction that the length of the string cannot be longer than nine characters. We can obtain the value of the string using the following code:
    Cusip       myCusip = "281C82UE";
    bsl::string base    = bdlat_CustomizedTypeFunctions::convertToBaseType(
                                                                    myCusip);

    assert("281C82UE" == base);
Attempting to assign a string longer than nine characters will not succeed:
    bsl::string invalidCusip = "1234567890";

    int retCode = bdlat_CustomizedTypeFunctions::convertFromBaseType(
                                                               &myCusip,
                                                               invalidCusip);

    assert(0 != retCode);
For the purpose of this example, the class definition is as follows:
  #include <bdlat_customizedtypefunctions.h>
  #include <bdlb_string.h>
  #include <bsls_assert.h>
  #include <sstream>
  #include <string>

  namespace BloombergLP {

  namespace mine {

  class Cusip {
     //  Identification number for the US and Canada.  It is a 9-digit number
     //  consisting of 8 digits and a check digit.  The Bloomberg ID will be
     // returned for Corp, Govt, Pfd if a CUSIP is not available.

    private:
      // PRIVATE DATA MEMBERS
      bsl::string d_value;  // stored value

      // FRIENDS
      friend bool operator==(const Cusip& lhs, const Cusip& rhs);
      friend bool operator!=(const Cusip& lhs, const Cusip& rhs);
    public:
      // TYPES
      typedef bsl::string BaseType;

      // CREATORS
      explicit Cusip(bslma::Allocator *basicAllocator = 0);
          // Create an object of type 'Cusip' having the default value.
          // Optionally specify a 'basicAllocator' used to supply memory.  If
          // 'basicAllocator' is 0, the currently installed default allocator
          // is used.

      Cusip(const Cusip& original, bslma::Allocator *basicAllocator = 0);
          // Create an object of type 'Cusip' having the value
          // of the specified 'original' object.  Optionally specify a
          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
          // 0, the currently installed default allocator is used.

      explicit Cusip(const bsl::string&  value,
                     bslma::Allocator   *basicAllocator = 0);
          // Create an object of type 'Cusip' having the specified 'value'.
          // Optionally specify a 'basicAllocator' used to supply memory.  If
          // 'basicAllocator' is 0, the currently installed default allocator
          // is used.

      ~Cusip();
          // Destroy this object.

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

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

      int fromString(const bsl::string& value);
         // Convert from the specified 'value' to this type.  Return 0 if
          // successful and non-zero otherwise.

      // 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.

      const bsl::string& toString() const;
          // Convert this value to 'bsl::string'.
  };

  // FREE OPERATORS
  inline
  bool operator==(const Cusip& lhs, const Cusip& 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 Cusip& lhs, const Cusip& 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 Cusip& rhs);
      // Format the specified 'rhs' to the specified output 'stream' and
      // return a reference to the modifiable 'stream'.
The class implementation is straightforward and is deferred to the end of this usage example.
We can now make Cusip expose "customized type" behavior by implementing bdlat_CustomizedTypeFunctions for Cusip. The first method (the longer one) overloads all the bdlat_customizedType* functions. In the second method, we show how to bypass this by simply declaring the class mine::Cusip to have the bdlat_TypeTraitBasicCustomizedType trait.
Longer Usage:
First, we should forward declare all the functions that we will implement inside the mine namespace:
      // MANIPULATORS
      template <typename TYPE, typename BASE_TYPE>
      int bdlat_customizedTypeConvertFromBaseType(TYPE             *object,
                                                  const BASE_TYPE&  value);
          // Convert from the specified 'value' to the specified customized
          // 'object'.  Return 0 if successful and non-zero otherwise.

      // ACCESSORS
      template <typename TYPE>
      const typename BaseType<TYPE>::Type&
      bdlat_customizedTypeConvertToBaseType(const TYPE& object);
          // Load into the specified 'result' the value of the specified
          // 'object'.

  } // close namespace 'mine'
Next, we provide the definitions for each of these functions:
 // MANIPULATORS
 template <typename TYPE, typename BASE_TYPE>
 int mine::bdlat_customizedTypeConvertFromBaseType(TYPE             *object,
                                                   const BASE_TYPE&  value);
 {
     return object->fromString(value);
 }

 // ACCESSORS
 template <typename TYPE>
 const typename BaseType<TYPE>::Type&
 mine::bdlat_customizedTypeConvertToBaseType(const TYPE& object);
 {
     return object.toString();
 }
Finally, we need to specialize the IsCustomizedType meta-function in the bdlat_CustomizedTypeFunctions namespace for the mine::Cusip type. This makes the bdlat infrastructure recognize mine::Cusip as a customized type abstraction:
  namespace bdlat_CustomizedTypeFunctions {

      template <>
      struct IsCustomizedType<mine::Cusip> {
          enum { VALUE = 1 };
      };

  } // close namespace 'bdlat_CustomizedTypeFunctions'
  } // close namespace 'BloombergLP'
The bdlat infrastructure (and any component that uses this infrastructure) will now recognize mine::Cusip as a "customized" type.
Shorter Usage:
We can bypass all the code from the longer usage example by simply declaring mine::Cusip to have the bdlat_TypeTraitBasicCustomizedType trait as follows: Again, the bdlat infrastructure (and any component that uses this infrastructure) will now recognize mine::Cusip as a "customized" type.
For example, suppose we have the following XML data:
  <?xml version='1.0' encoding='UTF-8' ?>
  <Cusip>
      <value>"281C82UE"</value>
  </Cusip>
Using the balxml_decoder component, we can load this XML data into a mine::Cusip object:
  #include <balxml_decoder.h>

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

      Cusip 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("281C82UE" == object.toString());
  }
Note that the bdlat framework can be used for functionality other than encoding/decoding into XML. When mine::Cusip is plugged into the framework, then it will be automatically usable within the framework. For example, the following snippets of code will convert a string from a stream and load it into a Cusip object:
  template <typename TYPE>
  int readCusip(bsl::istream& stream, TYPE *object)
  {
      bsl::string value;
      stream >> value;

      return bdlat_CustomizedType::convertFromBaseType(cusip, value);
  }
Now we have a generic function that takes an input stream and a Cusip object, and inputs its value. We can use this generic function as follows:
  void usageExample()
  {
      using namespace BloombergLP;

      bsl::stringstream ss;
      mine::Cusip object;

      ss << "281C82UE\n1234567890\n";

      assert(0          == readCusip(ss, &object));
      assert("281C82UE" == object.toString());

      assert(0          != readCusip(ss, &object));
  }
This concludes the usage example.
For completeness, we finish by providing the straightforward details of the implementation of the class Cusip:
  // CREATORS

  inline
  Cusip::Cusip(bslma::Allocator *basicAllocator)
  : d_value(basicAllocator)
  {
  }

  inline
  Cusip::Cusip(const Cusip& original, bslma::Allocator *basicAllocator)
  : d_value(original.d_value, basicAllocator)
  {
  }

  inline
  Cusip::Cusip(const bsl::string& value, bslma::Allocator *basicAllocator)
  : d_value(value, basicAllocator)
  {
  }

  inline
  Cusip::~Cusip()
  {
  }

  // MANIPULATORS

  inline
  Cusip& Cusip::operator=(const Cusip& rhs)
  {
      d_value = rhs.d_value;
      return *this;
  }

  inline
  void Cusip::reset()
  {
      // bdlat_ValueTypeFunctions::reset(&d_value);
      d_value.erase();
  }

  inline
  int Cusip::fromString(const bsl::string& value)
  {
      enum { SUCCESS = 0, FAILURE = -1 };

      globalFlag = 1;

      if (9 < value.size()) {
          return FAILURE;
      }

      d_value = value;

      return SUCCESS;
  }

  // ACCESSORS

  inline
  bsl::ostream& Cusip::print(bsl::ostream& stream,
                             int           level,
                             int           spacesPerLevel) const
  {
      return bdlb::PrintMethods::print(stream,
                                      d_value,
                                      level,
                                      spacesPerLevel);
  }

  inline
  const bsl::string& Cusip::toString() const
  {
      globalFlag = 2;

      return d_value;
  }

  // FREE OPERATORS

  inline
  bool geom::operator==(const geom::Cusip& lhs,
                                   const geom::Cusip& rhs)
  {
      return lhs.d_value == rhs.d_value;
  }

  inline
  bool geom::operator!=(const geom::Cusip& lhs,
                                   const geom::Cusip& rhs)
  {
      return lhs.d_value != rhs.d_value;
  }

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