BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlat_choicefunctions

Detailed Description

Outline

Purpose

Provide a namespace defining choice functions.

Classes

See also
bdlat_selectioninfo

Description

The bdlat_ChoiceFunctions namespace provided in this component defines parameterized functions that expose "choice" behavior for "choice" types. See the {bdlat} package-level documentation for a full description of "choice" types.

The functions in this namespace allow users to:

Also, the meta-function IsChoice contains a compile-time constant value that is non-zero if the parameterized TYPE exposes "choice" behavior through the bdlat_ChoiceFunctions namespace.

This component specializes all of these functions for types that have the bdlat_TypeTraitBasicChoice trait.

Types that do not have the bdlat_TypeTraitBasicChoice 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::MyChoice. In order to plug this type into the bdlat framework as a "Choice", the following functions must be declared and implemented in the mine namespace:

namespace mine {
// MANIPULATORS
int bdlat_choiceMakeSelection(MyChoice *object, int selectionId);
// Set the value of the specified 'object' to be the default for
// the selection indicated by the specified 'selectionId'. Return
// 0 on success, and non-zero value otherwise (i.e., the selection
// is not found).
int bdlat_choiceMakeSelection(MyChoice *object,
const char *selectionName,
int selectionNameLength);
// 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
// non-zero value otherwise (i.e., the selection is not found).
template <typename MANIPULATOR>
int bdlat_choiceManipulateSelection(MyChoice *object,
MANIPULATOR& manipulator);
// 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.
// ACCESSORS
template <typename ACCESSOR>
int bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor);
// 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.
int bdlat_choiceSelectionId(const MyChoice& object);
// Return the id of the current selection if the selection is
// defined, and 0 otherwise.
} // close namespace 'mine'

Also, the IsChoice meta-function must be specialized for the mine::MyChoice type in the bdlat_ChoiceFunctions namespace.

Usage

This section illustrates intended use of this component.

Example 1: Basic Usage

Suppose you had a union embedded inside a struct. The struct also contains a d_selectionId member that specifies which member of the union is selected. The default constructor of the struct makes the selection undefined:

namespace BloombergLP {
namespace mine {
struct MyChoice {
// This struct represents a choice between a 'char' value, an 'int'
// value, and a 'float' value.
// CONSTANTS
enum {
UNDEFINED_SELECTION_ID = -1,
CHAR_SELECTION_ID = 0,
INT_SELECTION_ID = 1,
FLOAT_SELECTION_ID = 2
};
// DATA MEMBERS
union {
char d_charValue;
int d_intValue;
float d_floatValue;
};
int d_selectionId;
// CREATORS
MyChoice()
: d_selectionId(UNDEFINED_SELECTION_ID)
{
}
};
@ UNDEFINED_SELECTION_ID
Definition bdlat_choicefunctions.h:514

We can now make MyChoice expose "choice" behavior by implementing bdlat_ChoiceFunctions for MyChoice. First, we should forward declare all the functions that we will implement inside the mine namespace:

// MANIPULATORS
int bdlat_choiceMakeSelection(MyChoice *object, int selectionId);
// Set the value of the specified 'object' to be the default for the
// selection indicated by the specified 'selectionId'. Return 0 on
// success, and non-zero value otherwise (i.e., the selection is not
// found).
int bdlat_choiceMakeSelection(MyChoice *object,
const char *selectionName,
int selectionNameLength);
// 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 non-zero
// value otherwise (i.e., the selection is not found).
template <class MANIPULATOR>
int bdlat_choiceManipulateSelection(MyChoice *object,
MANIPULATOR& manipulator);
// 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.
// ACCESSORS
template <class ACCESSOR>
int bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor);
// 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.
int bdlat_choiceSelectionId(const MyChoice& object);
// Return the id of the current selection if the selection is defined,
// and 0 otherwise.
} // close namespace mine

Now, we provide the definitions for each of these functions:

// MANIPULATORS
int mine::bdlat_choiceMakeSelection(MyChoice *object,
int selectionId)
{
enum { SUCCESS = 0, NOT_FOUND = -1 };
switch (selectionId) {
case MyChoice::CHAR_SELECTION_ID: {
object->d_selectionId = selectionId;
object->d_charValue = 0;
return SUCCESS; // RETURN
}
case MyChoice::INT_SELECTION_ID: {
object->d_selectionId = selectionId;
object->d_intValue = 0;
return SUCCESS; // RETURN
}
case MyChoice::FLOAT_SELECTION_ID: {
object->d_selectionId = selectionId;
object->d_floatValue = 0;
return SUCCESS; // RETURN
}
case MyChoice::UNDEFINED_SELECTION_ID: {
object->d_selectionId = selectionId;
return SUCCESS; // RETURN
}
default: {
return NOT_FOUND; // RETURN
}
}
}
int mine::bdlat_choiceMakeSelection(MyChoice *object,
const char *selectionName,
int selectionNameLength)
{
enum { NOT_FOUND = -1 };
selectionName,
selectionNameLength)) {
MyChoice::CHAR_SELECTION_ID);
// RETURN
}
selectionName,
selectionNameLength)) {
MyChoice::INT_SELECTION_ID);
// RETURN
}
selectionName,
selectionNameLength)) {
MyChoice::FLOAT_SELECTION_ID);
// RETURN
}
return NOT_FOUND;
}
int bdlat_choiceMakeSelection(TYPE *object, int selectionId)
int selectionId(const TYPE &object)
static bool areEqualCaseless(const char *lhsString, const char *rhsString)

For the manipulateSelection and accessSelection functions, we need to create a temporary bdlat_SelectionInfo object and pass it along when invoking the manipulator or accessor. See the bdlat_selectioninfo component-level documentation for more information. The implementation of the remaining functions are as follows:

template <class MANIPULATOR>
int mine::bdlat_choiceManipulateSelection(MyChoice *object,
MANIPULATOR& manipulator)
{
switch (object->d_selectionId) {
case MyChoice::CHAR_SELECTION_ID: {
info.annotation() = "Char Selection";
info.id() = MyChoice::CHAR_SELECTION_ID;
info.name() = "charValue";
info.nameLength() = 9;
return manipulator(&object->d_charValue, info); // RETURN
}
case MyChoice::INT_SELECTION_ID: {
info.annotation() = "Int Selection";
info.id() = MyChoice::INT_SELECTION_ID;
info.name() = "intValue";
info.nameLength() = 8;
return manipulator(&object->d_intValue, info); // RETURN
}
case MyChoice::FLOAT_SELECTION_ID: {
info.annotation() = "Float Selection";
info.id() = MyChoice::FLOAT_SELECTION_ID;
info.name() = "floatValue";
info.nameLength() = 10;
return manipulator(&object->d_floatValue, info); // RETURN
}
default:
BSLS_ASSERT_SAFE(0 == "Invalid selection!");
}
return 0;
}
// ACCESSORS
template <class ACCESSOR>
int mine::bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor)
{
switch (object.d_selectionId) {
case MyChoice::CHAR_SELECTION_ID: {
info.annotation() = "Char Selection";
info.id() = MyChoice::CHAR_SELECTION_ID;
info.name() = "charValue";
info.nameLength() = 9;
return accessor(object.d_charValue, info); // RETURN
}
case MyChoice::INT_SELECTION_ID: {
info.annotation() = "Int Selection";
info.id() = MyChoice::INT_SELECTION_ID;
info.name() = "intValue";
info.nameLength() = 8;
return accessor(object.d_intValue, info); // RETURN
}
case MyChoice::FLOAT_SELECTION_ID: {
info.annotation() = "Float Selection";
info.id() = MyChoice::FLOAT_SELECTION_ID;
info.name() = "floatValue";
info.nameLength() = 10;
return accessor(object.d_floatValue, info); // RETURN
}
default:
BSLS_ASSERT_SAFE(0 == "Invalid selection!");
}
return 0;
}
int mine::bdlat_choiceSelectionId(const MyChoice& object)
{
return object.d_selectionId;
}
int & id()
Definition bdlat_selectioninfo.h:256
int & nameLength()
Definition bdlat_selectioninfo.h:268
const char *& name()
Definition bdlat_selectioninfo.h:262
const char *& annotation()
Definition bdlat_selectioninfo.h:244
int & formattingMode()
Definition bdlat_selectioninfo.h:250
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
@ e_DEFAULT
Definition bdlat_formattingmode.h:110
Definition bdlat_selectioninfo.h:136

Finally, we need to specialize the IsChoice meta-function in the bdlat_ChoiceFunctions namespace for the mine::MyChoice type. This makes the bdlat infrastructure recognize mine::MyChoice as a choice abstraction:

template <>
struct IsChoice<mine::MyChoice> : bsl::true_type {
};
} // close namespace bdlat_ChoiceFunctions
} // close enterprise namespace
Definition bdlat_choicefunctions.h:504

The bdlat infrastructure (and any component that uses this infrastructure) will now recognize MyChoice as a "choice" type. For example, suppose we have the following XML data:

<?xml version='1.0' encoding='UTF-8' ?>
<MyChoice>
<intValue>321</intValue>
</MyChoice>

Using the balxml_decoder component, we can load this XML data into a MyChoice object:

void usageExample(bsl::istream& inputData)
{
using namespace BloombergLP;
MyChoice object;
assert(MyChoice::UNDEFINED_SELECTION_ID == object.d_selectionId);
balxml::Decoder decoder(&options, &reader, &errInfo);
int result = decoder.decode(inputData, &object);
assert(0 == result);
assert(MyChoice::INT_SELECTION_ID == object.d_selectionId);
assert(321 == object.d_intValue);
}
Definition balxml_decoderoptions.h:72
Definition balxml_decoder.h:402
Definition balxml_errorinfo.h:353
Definition balxml_minireader.h:343

Note that the bdlat framework can be used for functionality other than encoding/decoding into XML. When mine::MyChoice is plugged into the framework, then it will be automatically usable within the framework. For example, the following snippets of code will print out the selection value of a choice object:

struct PrintSelection {
// 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; // RETURN
}
};
template <class TYPE>
void printChoiceSelection(bsl::ostream& stream, const TYPE& object)
{
using namespace BloombergLP;
PrintSelection accessor;
accessor.d_stream_p = &stream;
bdlat_choiceAccessSelection(object, accessor);
}
int bdlat_choiceAccessSelection(const TYPE &object, ACCESSOR &accessor)

Now we have a generic function that takes an output stream and a choice object, and prints out each choice seletion with its name and value. We can use this generic function as follows:

void printMyChoice(bsl::ostream& stream)
{
using namespace BloombergLP;
mine::MyChoice object;
object.d_selectionId = mine::MyChoice::INT_SELECTION_ID;
object.d_intValue = 321;
printChoiceSelection(stream, object);
}

The function above will print the following to provided stream:

intValue: 321