// bdlat_choicefunctions.h -*-C++-*- // ---------------------------------------------------------------------------- // NOTICE // // This component is not up to date with current BDE coding standards, and // should not be used as an example for new development. // ---------------------------------------------------------------------------- #ifndef INCLUDED_BDLAT_CHOICEFUNCTIONS #define INCLUDED_BDLAT_CHOICEFUNCTIONS #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a namespace defining choice functions. // //@CLASSES: // bdlat_ChoiceFunctions: namespace for calling choice functions // //@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: //: o make a selection using either a selection id or a selection name //: ('makeSelection'), //: o manipulate the current selection using a parameterized manipulator //: ('manipulateSelection'), //: o access the current selection using a parameterized accessor //: ('accessSelection'), and //: o 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 { // // // 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 ///----- // 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) // { // } // }; //.. // 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 }; // // 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; // } //.. // 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: { // 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; // } //.. // 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: //.. // namespace bdlat_ChoiceFunctions { // // template <> // struct IsChoice<mine::MyChoice> { // enum { VALUE = 1 }; // }; // // } // close namespace bdlat_ChoiceFunctions // } // close enterprise namespace //.. // 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::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); // } //.. // 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); // } //.. // 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 //.. #include <bdlscm_version.h> #include <bdlat_bdeatoverrides.h> #include <bdlat_selectioninfo.h> #include <bdlat_typetraits.h> #include <bslalg_hastrait.h> #include <bslmf_assert.h> #include <bslmf_metaint.h> #include <bsls_assert.h> #include <bsls_platform.h> namespace BloombergLP { // =============================== // namespace bdlat_ChoiceFunctions // =============================== namespace bdlat_ChoiceFunctions { // This 'namespace' provides functions that expose "choice" behavior for // "choice" types. See the component-level documentation for more // information. // CONSTANTS enum { k_UNDEFINED_SELECTION_ID = -1 // indicates selection not made #ifndef BDE_OMIT_INTERNAL_DEPRECATED , UNDEFINED_SELECTION_ID = k_UNDEFINED_SELECTION_ID , BDEAT_UNDEFINED_SELECTION_ID = k_UNDEFINED_SELECTION_ID #endif // BDE_OMIT_INTERNAL_DEPRECATED }; // META-FUNCTIONS template <class TYPE> struct IsChoice { // This 'struct' should be specialized for third-party types that need // to expose "choice" behavior. See the component-level documentation // for further information. // TYPES enum { VALUE = bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE }; }; // MANIPULATORS template <class TYPE> int makeSelection(TYPE *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). template <class TYPE> int makeSelection(TYPE *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 TYPE, class MANIPULATOR> int manipulateSelection(TYPE *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 the value returned from the invocation of // 'manipulator'. The behavior is undefined unless // 'k_UNDEFINED_SELECTION_ID != selectionId(*object)'. // ACCESSORS template <class TYPE, class ACCESSOR> int accessSelection(const TYPE& 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 the value returned from the // invocation of 'accessor'. The behavior is undefined unless // 'k_UNDEFINED_SELECTION_ID != selectionId(object)'. template <class TYPE> bool hasSelection(const TYPE& object, const char *selectionName, int selectionNameLength); // Return true if the specified 'object' has a selection with the // specified 'selectionName' of the specified 'selectionNameLength', // and false otherwise. template <class TYPE> bool hasSelection(const TYPE& object, int selectionId); // Return true if the specified 'object' has a selection with the // specified 'selectionId', and false otherwise. template <class TYPE> int selectionId(const TYPE& object); // Return the id of the current selection if the selection is defined, // and k_UNDEFINED_SELECTION_ID otherwise. } // close namespace bdlat_ChoiceFunctions // ==================== // default declarations // ==================== namespace bdlat_ChoiceFunctions { // This namespace declaration adds the default implementations of the // "choice" customization-point functions to 'bdlat_ChoiceFunctions'. These // default implementations assume the type of the acted-upon object is a // basic-choice type. For more information about basic-choice types, see // {'bdlat_typetraits'}. // MANIPULATORS template <class TYPE> int bdlat_choiceMakeSelection(TYPE *object, int selectionId); template <class TYPE> int bdlat_choiceMakeSelection(TYPE *object, const char *selectionName, int selectionNameLength); template <class TYPE, class MANIPULATOR> int bdlat_choiceManipulateSelection(TYPE *object, MANIPULATOR& manipulator); // ACCESSORS template <class TYPE, class ACCESSOR> int bdlat_choiceAccessSelection(const TYPE& object, ACCESSOR& accessor); template <class TYPE> bool bdlat_choiceHasSelection(const TYPE& object, const char *selectionName, int selectionNameLength); template <class TYPE> bool bdlat_choiceHasSelection(const TYPE& object, int selectionId); template <class TYPE> int bdlat_choiceSelectionId(const TYPE& object); } // close namespace bdlat_ChoiceFunctions // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // ------------------------------- // namespace bdlat_ChoiceFunctions // ------------------------------- // MANIPULATORS template <class TYPE> inline int bdlat_ChoiceFunctions::makeSelection(TYPE *object, int selectionId) { return bdlat_choiceMakeSelection(object, selectionId); } template <class TYPE> inline int bdlat_ChoiceFunctions::makeSelection(TYPE *object, const char *selectionName, int selectionNameLength) { return bdlat_choiceMakeSelection(object, selectionName, selectionNameLength); } template <class TYPE, class MANIPULATOR> inline int bdlat_ChoiceFunctions::manipulateSelection(TYPE *object, MANIPULATOR& manipulator) { BSLS_ASSERT_SAFE(k_UNDEFINED_SELECTION_ID != bdlat_choiceSelectionId(*object)); return bdlat_choiceManipulateSelection(object, manipulator); } // ACCESSORS template <class TYPE, class ACCESSOR> inline int bdlat_ChoiceFunctions::accessSelection(const TYPE& object, ACCESSOR& accessor) { BSLS_ASSERT_SAFE(k_UNDEFINED_SELECTION_ID != bdlat_choiceSelectionId(object)); return bdlat_choiceAccessSelection(object, accessor); } template <class TYPE> inline bool bdlat_ChoiceFunctions::hasSelection(const TYPE& object, const char *selectionName, int selectionNameLength) { return bdlat_choiceHasSelection(object, selectionName, selectionNameLength); } template <class TYPE> inline bool bdlat_ChoiceFunctions::hasSelection(const TYPE& object, int selectionId) { return bdlat_choiceHasSelection(object, selectionId); } template <class TYPE> inline int bdlat_ChoiceFunctions::selectionId(const TYPE& object) { return bdlat_choiceSelectionId(object); } // ------------------- // default definitions // ------------------- // MANIPULATORS template <class TYPE> inline int bdlat_ChoiceFunctions::bdlat_choiceMakeSelection(TYPE *object, int selectionId) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return object->makeSelection(selectionId); } template <class TYPE> inline int bdlat_ChoiceFunctions::bdlat_choiceMakeSelection( TYPE *object, const char *selectionName, int selectionNameLength) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return object->makeSelection(selectionName, selectionNameLength); } template <class TYPE, class MANIPULATOR> inline int bdlat_ChoiceFunctions::bdlat_choiceManipulateSelection( TYPE *object, MANIPULATOR& manipulator) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return object->manipulateSelection(manipulator); } // ACCESSORS template <class TYPE, class ACCESSOR> inline int bdlat_ChoiceFunctions::bdlat_choiceAccessSelection(const TYPE& object, ACCESSOR& accessor) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return object.accessSelection(accessor); } template <class TYPE> inline bool bdlat_ChoiceFunctions::bdlat_choiceHasSelection( const TYPE& object, const char *selectionName, int selectionNameLength) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return 0 != object.lookupSelectionInfo(selectionName, selectionNameLength); } template <class TYPE> inline bool bdlat_ChoiceFunctions::bdlat_choiceHasSelection(const TYPE& object, int selectionId) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return 0 != object.lookupSelectionInfo(selectionId); } template <class TYPE> inline int bdlat_ChoiceFunctions::bdlat_choiceSelectionId(const TYPE& object) { BSLMF_ASSERT((bslalg::HasTrait<TYPE, bdlat_TypeTraitBasicChoice>::VALUE)); return object.selectionId(); } } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------