Quick Links: |
Provide a namespace defining choice functions. More...
Namespaces | |
namespace | bdlat_ChoiceFunctions |
bdlat_ChoiceFunctions | namespace for calling choice functions |
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. makeSelection
), manipulateSelection
), accessSelection
), and selectionId
). IsChoice
contains a compile-time constant VALUE
that is non-zero if the parameterized TYPE
exposes "choice" behavior through the bdlat_ChoiceFunctions
namespace
. bdlat_TypeTraitBasicChoice
trait. 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'
IsChoice
meta-function must be specialized for the mine::MyChoice
type in the bdlat_ChoiceFunctions
namespace. 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) { } };
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
// 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 }; if (bdlb::String::areEqualCaseless("charValue", selectionName, selectionNameLength)) { return bdlat_choiceMakeSelection(object, MyChoice::CHAR_SELECTION_ID); // RETURN } if (bdlb::String::areEqualCaseless("intValue", selectionName, selectionNameLength)) { return bdlat_choiceMakeSelection(object, MyChoice::INT_SELECTION_ID); // RETURN } if (bdlb::String::areEqualCaseless("floatValue", selectionName, selectionNameLength)) { return bdlat_choiceMakeSelection(object, MyChoice::FLOAT_SELECTION_ID); // RETURN } return NOT_FOUND; }
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: { bdlat_SelectionInfo info; info.annotation() = "Char Selection"; info.formattingMode() = bdlat_FormattingMode::e_DEFAULT; info.id() = MyChoice::CHAR_SELECTION_ID; info.name() = "charValue"; info.nameLength() = 9; return manipulator(&object->d_charValue, info); // RETURN } case MyChoice::INT_SELECTION_ID: { bdlat_SelectionInfo info; info.annotation() = "Int Selection"; info.formattingMode() = bdlat_FormattingMode::e_DEFAULT; info.id() = MyChoice::INT_SELECTION_ID; info.name() = "intValue"; info.nameLength() = 8; return manipulator(&object->d_intValue, info); // RETURN } case MyChoice::FLOAT_SELECTION_ID: { bdlat_SelectionInfo info; info.annotation() = "Float Selection"; info.formattingMode() = bdlat_FormattingMode::e_DEFAULT; info.id() = MyChoice::FLOAT_SELECTION_ID; info.name() = "floatValue"; info.nameLength() = 10; return manipulator(&object->d_floatValue, info); // RETURN } default: BSLS_ASSERT_SAFE(!"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: { bdlat_SelectionInfo info; info.annotation() = "Char Selection"; info.formattingMode() = bdlat_FormattingMode::e_DEFAULT; info.id() = MyChoice::CHAR_SELECTION_ID; info.name() = "charValue"; info.nameLength() = 9; return accessor(object.d_charValue, info); // RETURN } case MyChoice::INT_SELECTION_ID: { bdlat_SelectionInfo info; info.annotation() = "Int Selection"; info.formattingMode() = bdlat_FormattingMode::e_DEFAULT; info.id() = MyChoice::INT_SELECTION_ID; info.name() = "intValue"; info.nameLength() = 8; return accessor(object.d_intValue, info); // RETURN } case MyChoice::FLOAT_SELECTION_ID: { bdlat_SelectionInfo info; info.annotation() = "Float Selection"; info.formattingMode() = bdlat_FormattingMode::e_DEFAULT; info.id() = MyChoice::FLOAT_SELECTION_ID; info.name() = "floatValue"; info.nameLength() = 10; return accessor(object.d_floatValue, info); // RETURN } default: BSLS_ASSERT_SAFE(!"Invalid selection!"); } return 0; } int mine::bdlat_choiceSelectionId(const MyChoice& object) { return object.d_selectionId; }
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: namespace bdlat_ChoiceFunctions { template <> struct IsChoice<mine::MyChoice> { enum { VALUE = 1 }; }; } // close namespace bdlat_ChoiceFunctions } // close enterprise namespace
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>
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::DecoderOptions options; balxml::MiniReader reader; balxml::ErrorInfo errInfo; 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); }
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); }
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); }
intValue: 321