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:
- make a selection using either a selection id or a selection name (
makeSelection
),
- manipulate the current selection using a parameterized manipulator (
manipulateSelection
),
- access the current selection using a parameterized accessor (
accessSelection
), and
- obtain the id for the current selection (
selectionId
).
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 {
int bdlat_choiceMakeSelection(MyChoice *object, int selectionId);
int bdlat_choiceMakeSelection(MyChoice *object,
const char *selectionName,
int selectionNameLength);
template <typename MANIPULATOR>
int bdlat_choiceManipulateSelection(MyChoice *object,
MANIPULATOR& manipulator);
template <typename ACCESSOR>
int bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor);
int bdlat_choiceSelectionId(const MyChoice& object);
}
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 {
enum {
UNDEFINED_SELECTION_ID = -1,
CHAR_SELECTION_ID = 0,
INT_SELECTION_ID = 1,
FLOAT_SELECTION_ID = 2
};
union {
char d_charValue;
int d_intValue;
float d_floatValue;
};
int d_selectionId;
MyChoice()
{
}
};
@ 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:
int bdlat_choiceMakeSelection(MyChoice *object, int selectionId);
int bdlat_choiceMakeSelection(MyChoice *object,
const char *selectionName,
int selectionNameLength);
template <class MANIPULATOR>
int bdlat_choiceManipulateSelection(MyChoice *object,
MANIPULATOR& manipulator);
template <class ACCESSOR>
int bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor);
int bdlat_choiceSelectionId(const MyChoice& object);
}
Now, we provide the definitions for each of these functions:
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;
}
case MyChoice::INT_SELECTION_ID: {
object->d_intValue = 0;
return SUCCESS;
}
case MyChoice::FLOAT_SELECTION_ID: {
object->d_floatValue = 0;
return SUCCESS;
}
case MyChoice::UNDEFINED_SELECTION_ID: {
return SUCCESS;
}
default: {
return NOT_FOUND;
}
}
}
int mine::bdlat_choiceMakeSelection(MyChoice *object,
const char *selectionName,
int selectionNameLength)
{
enum { NOT_FOUND = -1 };
selectionName,
selectionNameLength)) {
MyChoice::CHAR_SELECTION_ID);
}
selectionName,
selectionNameLength)) {
MyChoice::INT_SELECTION_ID);
}
selectionName,
selectionNameLength)) {
MyChoice::FLOAT_SELECTION_ID);
}
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.
id() = MyChoice::CHAR_SELECTION_ID;
info.
name() =
"charValue";
return manipulator(&object->d_charValue, info);
}
case MyChoice::INT_SELECTION_ID: {
info.
id() = MyChoice::INT_SELECTION_ID;
info.
name() =
"intValue";
return manipulator(&object->d_intValue, info);
}
case MyChoice::FLOAT_SELECTION_ID: {
info.
id() = MyChoice::FLOAT_SELECTION_ID;
info.
name() =
"floatValue";
return manipulator(&object->d_floatValue, info);
}
default:
}
return 0;
}
template <class ACCESSOR>
int mine::bdlat_choiceAccessSelection(const MyChoice& object,
ACCESSOR& accessor)
{
switch (object.d_selectionId) {
case MyChoice::CHAR_SELECTION_ID: {
info.
id() = MyChoice::CHAR_SELECTION_ID;
info.
name() =
"charValue";
return accessor(object.d_charValue, info);
}
case MyChoice::INT_SELECTION_ID: {
info.
id() = MyChoice::INT_SELECTION_ID;
info.
name() =
"intValue";
return accessor(object.d_intValue, info);
}
case MyChoice::FLOAT_SELECTION_ID: {
info.
id() = MyChoice::FLOAT_SELECTION_ID;
info.
name() =
"floatValue";
return accessor(object.d_floatValue, info);
}
default:
}
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
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 <>
};
}
}
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);
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 {
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 printChoiceSelection(bsl::ostream& stream, const TYPE& object)
{
using namespace BloombergLP;
PrintSelection accessor;
accessor.d_stream_p = &stream;
}
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: