BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlat_choicefunctions

Detailed Description

Provide a namespace defining choice functions.

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 brief 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. Note that the placeholder YOUR_TYPE is not a template argument and should be replaced with the name of the type being plugged into the framework.

// MANIPULATORS
/// 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(YOUR_TYPE *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 non-zero value
/// otherwise (i.e., the selection is not found).
int bdlat_choiceMakeSelection(YOUR_TYPE *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. The supplied
/// `manipulator` must be a callable type that can be called as if it had
/// the following signature:
/// ```
/// template <class t_INFO>
/// int manipulator(SELECTION_TYPE *selection, const t_INFO& info);
/// ```
/// Return -1 if the selection is undefined, and the value returned from the
/// invocation of `manipulator` otherwise.
template <typename MANIPULATOR>
int bdlat_choiceManipulateSelection(YOUR_TYPE *object,
MANIPULATOR& manipulator);
// ACCESSORS
/// Invoke the specified `accessor` on the (non-modifiable) selection of the
/// specified `object`, supplying `accessor` with the corresponding
/// selection information structure. The supplied `accessor` must be a
/// callable type that can be called as if it had the following signature:
/// ```
/// template <class t_INFO>
/// int accessor(const SELECTION_TYPE& selection, const t_INFO& info);
/// ```
/// Return -1 if the selection is undefined, and the value returned from the
/// invocation of `accessor` otherwise.
template <typename ACCESSOR>
int bdlat_choiceAccessSelection(const YOUR_TYPE& object,
ACCESSOR& accessor);
/// Return the id of the current selection if the selection is defined, and
/// 0 otherwise.
int bdlat_choiceSelectionId(const YOUR_TYPE& object);

Also, the IsChoice meta-function must be specialized for the YOUR_TYPE 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 {
/// This struct represents a choice between a `char` value, an `int` value,
/// and a `float` value.
struct MyChoice {
// 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:518

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
/// 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, 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 non-zero value
/// otherwise (i.e., the selection is not found).
int bdlat_choiceMakeSelection(MyChoice *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 MANIPULATOR>
int bdlat_choiceManipulateSelection(MyChoice *object,
MANIPULATOR& manipulator);
// ACCESSORS
/// 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 ACCESSOR>
int bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor);
/// Return the id of the current selection if the selection is defined, and
/// 0 otherwise.
int bdlat_choiceSelectionId(const MyChoice& object);
} // 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(ChoiceRef *ref, int selectionId)
Definition bdlar_choiceref.h:328
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:260
int & nameLength()
Definition bdlat_selectioninfo.h:272
const char *& name()
Definition bdlat_selectioninfo.h:266
const char *& annotation()
Definition bdlat_selectioninfo.h:248
int & formattingMode()
Definition bdlat_selectioninfo.h:254
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
@ e_DEFAULT
Definition bdlat_formattingmode.h:114
Definition bdlat_selectioninfo.h:138

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 bdlar_choiceref.h:499

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)
{
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:404
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:

/// Print each visited object to the bound `d_stream_p` object.
struct PrintSelection {
// 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)
{
PrintSelection accessor;
accessor.d_stream_p = &stream;
bdlat_choiceAccessSelection(object, accessor);
}
int bdlat_choiceAccessSelection(const ChoiceRef &ref, t_ACCESSOR &accessor)
Definition bdlar_choiceref.h:350

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)
{
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