// bdlat_typecategory.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_TYPECATEGORY #define INCLUDED_BDLAT_TYPECATEGORY #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide type category tags and a tag selection meta-function. // //@CLASSES: // bdlat_TypeCategory::Array : tag for array types // bdlat_TypeCategory::Choice : tag for choice types // bdlat_TypeCategory::CustomizedType : tag for customized types // bdlat_TypeCategory::DynamicType : tag for customized types // bdlat_TypeCategory::Enumeration : tag for enumeration types // bdlat_TypeCategory::NullableValue : tag for nullable types // bdlat_TypeCategory::Sequence : tag for sequence types // bdlat_TypeCategory::Simple : tag for simple types // bdlat_TypeCategory::Select : meta-function for selecting tag // bdlat_TypeCategoryDeclareDynamic : trait to declare dynamic type // bdlat_TypeCategoryFunctions : overloadable type category functions // bdlat_TypeCategoryUtil : type category utility // //@SEE_ALSO: bdlat_arrayfunctions, bdlat_choicefunctions, // bdlat_customizedtypefunctions, bdlat_enumfunctions, // bdlat_nullablevaluefunctions, bdlat_sequencefunctions // //@DESCRIPTION: This component provides an assortment of related facilities // that fulfill different roles when writing applications that deal with // classes that comply with the various 'bdlat' class categories. This // facilities consist of: //: o Tags and associated enumerators //: o Meta-functions and traits //: o Utility Functions //: o Customization Points // ///Category Tags and Enumerators ///----------------------------- // This component defines tag types (e.g., 'bdlat_TypeCategory::Array', // 'bdlat_TypeCategory::Choice') and enumerators (e.g., // 'bdlat_TypeCategory::e_ARRAY_CATEGORY' // 'bdlat_TypeCategory::e_CHOICE_CATEGORY') that can be used to describe how a // user-defined type participates in the 'bdlat' type framework and a // meta-function, 'bdlat_TypeCategory::Select', that can be used to access that // information for a parameterized 'TYPE'. // // The categories and their associated tags are: //.. // Category Tag Assigned To // ------------ ----------- // Array types that expose "array" behavior through the // 'bdlat_ArrayFunctions' 'namespace'. // // Choice types that expose "choice" behavior through the // 'bdlat_ChoiceFunctions' 'namespace'. // // CustomizedType types that expose "customized type" behavior through the // 'bdlat_CustomizedTypeFunctions' 'namespace'. // // DynamicType types that can select a category at runtime // // Enumeration types that expose "enumeration" behavior through the // 'bdlat_EnumFunctions' 'namespace'. // // NullableValue types that expose "nullable" behavior through the // 'bdlat_NullableValueFunctions' 'namespace'. // // Sequence types that expose "sequence" behavior through the // 'bdlat_SequenceFunctions' 'namespace'. // // Simple all other types (i.e., scalars) //.. // Types that belong to the 'DynamicType' category also belong to one or more // other categories. Otherwise, a type may only belong to one category. // ///Meta-function: 'bdlat::TypeCategory::Select' ///-------------------------------------------- // This component defines a meta-function, 'bdlat_TypeCategory::Select', used // to detect at compile time the type category of a template parameter 'TYPE', // which must be a 'bdlat'-compatible type. This meta-function defines two // (nested) names: // //: o 'Type': The category tag type for the template parameter 'TYPE'. //: o 'e_SELECTION': The enumerator for the category of the template parameter //: 'TYPE'. // // This meta-function assumes that the template parameter 'TYPE' has set the // type trait corresponding to its 'bdlat' type category. For example, if // 'TYPE' is a 'bdlat' "array" type then: //.. // 1 == bdlat_ArrayFunctions::IsArray<TYPE>::VALUE; //.. // and if 'TYPE' is a 'bdlat' "choice" type then: //.. // 1 == bdlat_ChoiceFunctions::IsChoice<TYPE>::VALUE; //.. // Additionally, 'TYPE' must also meet the other requirements (e.g., defined // functions, defined types) of its 'bdlat' type category. // // There are two special cases: // //: o If none of these traits have been set for 'TYPE', it is assumed to be in //: the 'Simple' (scalar) category. //: //: o If more than one of these traits have been set of 'TYPE', 'TYPE' is //: classified as 'Dynamic'. //: //: o The recommended practice is *also* set the //: 'bdlat_TypeCategoryDeclareDynamic' trait. // ///Utility: 'bdlat_TypeCategoryUtil' ///--------------------------------- // This component defines a utility 'struct', 'bdlat_TypeCategoryUtil', that // provides two function templates: 'manipulateByCategory' and // 'accessByCategory' that invoke a 'MANIPULATOR' or 'ACCESSOR' functor, // respectively. Both of these functor types provide an overload for each of // the 'bdlat' type categories (see {'MANIPULATOR' Functors} and {'ACCESSOR' // Functors}). These utility functions determine the 'bdlat' type category // (see {'bdlat_TypeCategoryFunctions::select'}) of a given object and then // invoke the corresponding overload of the given functor. // ///'MANIPULATOR' Functors /// - - - - - - - - - - - // A 'MANIPULATOR' functor must be invocable by one or more of these seven // overloads: //.. // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::Array category); // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::Choice category); // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::CustomizedType category); // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::Enumeration category); // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::NullableValue category); // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::Sequence category); // int MANIPULATOR(TYPE *object, bdlat_TypeCategory::Simple category); // // Modify the specified 'object' that matches the specified 'category'. // // Return 0 on success and a non-zero value otherwise. On failure, // // 'object' is left in a valid but unspecified state. The behavior is // // undefined unless the type category of 'object' matches 'category'. //.. // Notice that, potentially, one can have an overload for each of the "static" // 'bdlat' type categories (i.e., all except for the "dynamic" category). // // Additionally, the functor *must* provide an overload for 'bslmf::Nil' // (required for compilation): //.. // // int MANIPULATOR(TYPE *object, bslmf::Nil); // // Modify the specified 'object'. Return 0 on success and a non-zero // // value otherwise. On failure, 'object' is left in a valid but // // unspecified state. The behavior is undefined if 'TYPE' is 'bdlat' // // compatible (i.e., belongs in one or more of the seven 'bdlat' // // categories). Note that 'bdlat' compatible types are expected to be // // dispatched to one of the seven overloads declared above. //.. // Typically, the "Nil" overload returns an error code (or even aborts). // ///'ACCESSOR' Functors ///- - - - - - - - - - // A 'ACCESSOR' functor must invocable by one or more of these seven overloads: //.. // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::Array cat); // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::Choice cat); // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::CustomizedType cat); // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::Enumeration cat); // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::NullableValue cat); // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::Sequence cat); // int ACCESSOR(const TYPE& object, bdlat_TypeCategory::Simple cat); // // Access the specified 'object' that matches the specified 'cat' // // (category). Return 0 on success and a non-zero value otherwise. // // The behavior is undefined unless the type category of 'object' // // matches 'cat' (category). Note that, in typical use, invocation of // // this functor object changes its state based on the state of // // 'object'. //.. // Notice that, potentially, one can have an overload for each of the "static" // 'bdlat' type categories (i.e., all except for the "dyanamic" category). // // Additionally, the functor *must* provide an overload for 'bslmf::Nil' // (required for compilation): //.. // int ACCESSOR(const TYPE& object, bslmf::Nil); // // Access the specified 'object'. Return 0 on success and a non-zero // // value otherwise. The behavior is undefined if 'TYPE' is 'bdlat' // // compatible (i.e., belongs in one or more of the seven 'bdlat' // // categories). Note that 'bdlat' compatible types are expected to be // // dispatched to one of the seven overloads declared above. //.. // Typically, the "Nil" overload returns an error code (or even aborts). // ///Namespace: 'bdlat_TypeCategoryFunctions' ///--------------------------------------- // The namespace 'bdlat_TypeCategoryFunctions' defines a suite of function // templates for working with types that conform to one or more of the 'bdlat' // type categories. For each of the seven type categories there are a pair of // function templates: one to "manipulate" and one to "access" objects of // (template parameter) 'TYPE'. For example, for 'bdlat' "array" types there // are function templates: 'bdlat_TypeCategoryFunctions::manipulateArray' and // 'bdlat_TypeCategoryFunctions::accessArray'. // // Additionally, there is a function template, // 'bdlat_TypeCategoryFunctions::select', that reports at runtime the type // category of a specified object. // // These function templates provide a uniform interface for operations on a // wide variety of types. The details of what occurs in each "manipulate" or // "access" action depends on a user-provided functor object. See // {'MANIPULATOR' Functors} and {'ACCESSOR' Functors} for the requirements on // those functors. // // For a user-defined type to operate in the type category framework, that type // must define in the namespace in which it is defined, all required overloads // of the customization points used by these templates. See {Customization // Points}. // ///Customization Points /// - - - - - - - - - - // For a type to work with the "type category" framework, one must create, in // the namespace where the type is defined, overloads for the "manipulator" and // "accessor" function templates (described below) for the 'bdlat' type // category of the type. For example, if the type being plugged into the // framework is a 'bdlat' "array" type, then overloads for // 'bdlat_typeCategoryManipulateArray' and 'bdlat_typeCategoryAccessArray' are // required. If the type being plugged into the infrastructure belongs to more // than one 'bdlat' type category, the "manipulate" and "accessor" function // templates for each of those type categories is required. // // Every type plugged into the framework must implement an overload of // 'bdlat_typeCategorySelect' function. // // 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 // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateArray(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Array' // // tag object (2nd argument). If 'object' is not a 'bdlat' "array" // // type, pass a 'bslmf::Nil' tag object as the second argument. See // // {'MANIPULATOR' Functors} for the requirements on 'manipulator'. // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateChoice(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Choice' // // tag object (2nd argument). If 'object' is not a 'bdlat' "choice" // // type, pass a 'bslmf::Nil' tag object as the second argument. See // // {'MANIPULATOR' Functors} for the requirements on 'manipulator'. // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateCustomizedType(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::CustomizedType' tag object (2nd argument). If // // 'object' is not a 'bdlat' "customized type" type, pass a // // 'bslmf::Nil' tag object as the second argument. See {'MANIPULATOR' // // Functors} for the requirements on 'manipulator'. // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateEnumeration(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::Enumeration' tag object (2nd argument). If // // 'object' is not a 'bdlat' "enumeration" type, pass a 'bslmf::Nil' // // tag object as the second argument. See {'MANIPULATOR' Functors} for // // the requirements on 'manipulator'. // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateNullableValue(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::NullableValue' tag object (2nd argument). If // // 'object' is not a 'bdlat' "nullable value" type, pass a 'bslmf::Nil' // // tag object as the second argument. See {'MANIPULATOR' Functors} for // // the requirements on 'manipulator'. // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateSequence(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::Sequence' tag object (2nd argument). If // // 'object' is not a 'bdlat' "sequence" type, pass a 'bslmf::Nil' tag // // object as the second argument. See {'MANIPULATOR' Functors} for the // // requirements on 'manipulator'. // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateSimple(YOUR_TYPE *object, // MANIPULATOR& manipulator); // // Return the result of invoking the specified 'manipulator' with the // // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Simple' // // tag object (2nd argument). If 'object' is not a 'bdlat' "simple" // // type, pass a 'bslmf::Nil' tag object as the second argument. See // // {'MANIPULATOR' Functors} for the requirements on 'manipulator'. // // // ACCESSORS // template <class ACCESSOR> // int bdlat_typeCategoryAccessArray(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Array' // // tag object (2nd argument). If 'object' is not a 'bdlat' "array" // // type, pass a 'bslmf::Nil' tag object as the second argument. See // // {'ACCESSOR' Functors} for the requirements on 'accessor'. // // template <class ACCESSOR> // int bdlat_typeCategoryAccessChoice(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Choice' // // tag object (2nd argument). If 'object' is not a 'bdlat' "choice" // // type, pass a 'bslmf::Nil' tag object as the second argument. See // // {'ACCESSOR' Functors} for the requirements on 'accessor'. // // template <class ACCESSOR> // int bdlat_typeCategoryAccessCustomizedType(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::CustomizedType' tag object (2nd argument). If // // 'object' is not a 'bdlat' "customized type" type, pass a // // 'bslmf::Nil' tag object as the second argument. See {'ACCESSOR' // // Functors} for the requirements on 'accessor'. // // template <class ACCESSOR> // int bdlat_typeCategoryAccessEnumeration(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::Enumeration' tag object (2nd argument). If // // 'object' is not a 'bdlat' "enumeration type" type, pass a // // 'bslmf::Nil' tag object as the second argument. See {'ACCESSOR' // // Functors} for the requirements on 'accessor'. // // template <class ACCESSOR> // int bdlat_typeCategoryAccessNullableValue(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::NullableValue' tag object (2nd argument). If // // 'object' is not a 'bdlat' "nullable value" type, pass a 'bslmf::Nil' // // tag object as the second argument. See {'ACCESSOR' Functors} for // // the requirements on 'accessor'. // // template <class ACCESSOR> // int bdlat_typeCategoryAccessSequence(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a // // 'bdlat_TypeCategory::Sequence' tag object (2nd argument). If // // 'object' is not a 'bdlat' "sequence" type, pass a 'bslmf::Nil' tag // // object as the second argument. See {'ACCESSOR' Functors} for the // // requirements on 'accessor'. // // template <class ACCESSOR> // int bdlat_typeCategoryAccessSimple(const YOUR_TYPE& object, // ACCESSOR& accessor); // // Return the result of invoking the specified 'accessor' with the // // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Simple' // // tag object (2nd argument). If 'object' is not a 'bdlat' "simple" // // type, pass a 'bslmf::Nil' tag object as the second argument. See // // {'ACCESSOR' Functors} for the requirements on 'accessor'. // // bdlat_TypeCategory::Value bdlat_typeCategorySelect( // const YOUR_TYPE& object); // // Return the *runtime* type category for the specified 'object'. The // // behavior is undefined if 'bdlat_TypeCategory::e_DYNAMIC_CATEGORY' is // // returned. Note that the compile time analog to this function // // (template) is 'bdlat_TypeCategory::Select', a meta-function that // // defines a type corresponding to the category tag class of // // 'YOUR_TYPE'. //.. // ///Dynamic Types ///------------- // "Dynamic" types allow the type category of an object to be determined at // runtime. Of course, such types must meet all of the requirements of each of // the 'bdlat' type categories to which they belong. // // There are two ways that a type can be recognized as a dynamic type: // //: o specializing the 'bdlat_TypeCategoryDeclareDynamic' trait and providing a //: 'VALUE' of 1, and //: //: o implementing all of the requirements (i.e., setting of required traits) //: of each of the 'bdlat' categories the type can assume. // // If a type 'T' is recognized as a "dynamic" 'bdlat' type then // 'bdlat_TypeCategory::Select<T>::Type' is an alias for // 'bdlat_TypeCategory::DynamicType' // // When a type is categorized as a dynamic type, it *must* overload the // 'bdlat_TypeCategoryFunctions::select' function to provide the necessary // runtime logic that determines its current runtime category. See // {Customization Points}. // // A type of the 'bdlat' "dyanmic" category is illustrated in {Example 3}. // ///Trait: 'bdlat_TypeCategoryDeclareDynamic' ///- - - - - - - - - - - - - - - - - - - - - // Although one is not required to specialize the // 'bdlat_TypeCategoryDeclareDynamic' trait to designate a user-defined class // as a "dynamic" type, doing so is the recommended practice. // // Note that AIX and GCC compilers *require* that trait be specialized; setting // multiple 'bdlat' category traits does not work on those platforms. // // Also note that setting that trait is the only way to create a "dynamic" type // that implements just one of the 'bdlat' type categories -- an unusual // configuration, but one that is allowed by the 'bdlat" type category // framework. // // Finally note that the 'bdlat_TypeCategoryDeclareDynamic' trait is the *only* // trait in this component that users are allowed to specialize. The behavior // is undefined if any of the other meta-functions are specialized. // ///Usage ///----- // In this section we show intended usage of this component. // ///Example 1: Compile-Time Dispatch by Category Type ///- - - - - - - - - - - - - - - - - - - - - - - - - // The 'bdlat_typecategory' framework provides facilities to control actions // based on the 'bdlat' type category of the objects being used. Dispatching // on type category can be achieved both at compile time and at runtime. // Depending on that context, different facilities, having different // restrictions/requirements are used. There are interesting differences when // dealing with objects in the "dynamic" type category. // // This first example explores compile-time dispatch. Suppose we have an // object that is compliant with one of the 'bdlat' type categories and that we // wish to examine it to the extent of determining into which type category it // falls and what value it has. // // First, we declare a 'printCategoryAndValue' function that has a template // parameter 'TYPE': //.. // namespace BloombergLP { // namespace mine { // // template <class TYPE> // void printCategoryAndValue(bsl::ostream& stream, const TYPE& object); // // Print the category of the specified 'object' followed by the value // // of 'object' to the specified output 'stream'. //.. // Then, to implement this function, we will use a set of helper functions that // are overloaded based on the category tag. The first set of helper functions // address the category aspect of our assigned goal: //.. // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::Array) // { // stream << "Array"; // } // // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::Choice) // { // stream << "Choice"; // } // // void printCategory(bsl::ostream& stream, // bdlat_TypeCategory::CustomizedType) // { // stream << "CustomizedType"; // } // // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::DynamicType) // { // stream << "DynamicType"; // } // // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::Enumeration) // { // stream << "Enumeration"; // } // // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::NullableValue) // { // stream << "NullableValue"; // } // // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::Sequence) // { // stream << "Sequence"; // } // // void printCategory(bsl::ostream& stream, bdlat_TypeCategory::Simple) // { // stream << "Simple"; // } //.. // Next, we implement another helper function template to handle the value // aspect of our goal: //.. // template <class TYPE, class CATEGORY> // void printValue(bsl::ostream& stream, // const TYPE& object, // CATEGORY ) // { // bdlb::PrintMethods::print(stream, object, 0, -1); // } // // template <class TYPE> // void printValue(bsl::ostream& stream, // const TYPE& , // bdlat_TypeCategory::DynamicType ) // { // stream << "Printing dynamic types requires extra work."; // } //.. // Notice that a partial specialization was created for objects falling into // the "dynamic" category. Determining the value of such objects will be // explored in {Example 3}. // // Now, we can implement the 'printCategoryAndValue' function in terms of the // 'printCategory' and 'printValue' helper functions: //.. // // template <class TYPE> // void printCategoryAndValue(bsl::ostream& stream, const TYPE& object) // { // typedef typename // bdlat_TypeCategory::Select<TYPE>::Type TypeCategory; // // printCategory(stream, TypeCategory()); // // stream << ": "; // // printValue(stream, object, TypeCategory()); // } // // } // close package namespace // } // close enterprise namespace //.. // Finally, we can exercise the 'printCategoryAndValue' function on objects // that fall in different (non-dynamic) type categories. //.. // using namespace BloombergLP; // // void runUsageExample1() // { // bsl::ostringstream oss; // // int intVal = 123; // // mine::printCategoryAndValue(oss, intVal); // assert("Simple: 123" == oss.str()); // oss.str(""); // // bdlb::NullableValue<int> nullableInt; // // mine::printCategoryAndValue(oss, nullableInt); // assert("NullableValue: NULL" == oss.str()); // oss.str(""); // // nullableInt = 321; // // mine::printCategoryAndValue(oss, nullableInt); // assert("NullableValue: 321" == oss.str()); // oss.str(""); // // bsl::vector<int> vec; // // vec.push_back(123); // vec.push_back(345); // vec.push_back(987); // // mine::printCategoryAndValue(oss, vec); // assert("Array: [ 123 345 987 ]" == oss.str()); // } //.. // ///Example 2: Run-Time Dispatch by 'bdlat_TypeCategoryUtil' /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - // For run-time dispatching we can use the utility functions provided by // 'bdlat_TypeCategoryUtil'. Suppose we wish to examine the type category and // value of an arbitrary 'bdlat' compatible object, as we did in {Example 1}. // // First, we define 'mine::PrintAccessor', a functor that encapsulates the // action to be taken: //.. // namespace BloombergLP { // namespace mine { // // class PrintAccessor { // // bsl::ostream *d_stream_p; // // public: // PrintAccessor(bsl::ostream *stream) // : d_stream_p(stream) { assert(stream); } // // template <class TYPE> // int operator()(const TYPE& , bslmf::Nil ) // { // *d_stream_p << "Nil"; // return -1; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::Array) // { // *d_stream_p << "Array" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::Choice) // { // *d_stream_p << "Choice" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::CustomizedType) // { // *d_stream_p << "CustomizedType" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::Enumeration) // { // *d_stream_p << "Enumeration" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::NullableValue) // { // *d_stream_p << "NullableValue" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::Sequence) // { // *d_stream_p << "Sequence" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // // template <class TYPE> // int operator()(const TYPE& object, bdlat_TypeCategory::Simple) // { // *d_stream_p << "Simple" << ": "; // bdlb::PrintMethods::print(*d_stream_p, object, 0, -1); // return 0; // } // }; // // } // close package namespace // } // close enterprise namespace //.. // Notice that this overload set for 'operator()' includes an overload for // 'bslmf::Nil' (as required) but does *not* include an overload for // 'bdlat_TypeCategory::DynamicType' which is never reported as a runtime type // category. // // Now, we can simply use 'bdlat_TypeCategoryUtil' to determine the type of a // given object dispatch control to the corresponding overload of the accessor // functor: //.. // using namespace BloombergLP; // // void runUsageExample2() // { // bsl::ostringstream oss; // mine::PrintAccessor accessor(&oss); // // int intVal = 123; // // bdlat_TypeCategoryUtil::accessByCategory(intVal, accessor); // assert("Simple: 123" == oss.str()); // oss.str(""); // // bdlb::NullableValue<int> nullableInt; // // bdlat_TypeCategoryUtil::accessByCategory(nullableInt, accessor); // assert("NullableValue: NULL" == oss.str()); // oss.str(""); // // nullableInt = 321; // // bdlat_TypeCategoryUtil::accessByCategory(nullableInt, accessor); // assert("NullableValue: 321" == oss.str()); // oss.str(""); // // bsl::vector<int> vec; // // vec.push_back(123); // vec.push_back(345); // vec.push_back(987); // // bdlat_TypeCategoryUtil::accessByCategory(vec, accessor); // LOOP_ASSERT(oss.str(), "Array: [ 123 345 987 ]" == oss.str()); // oss.str(""); // } //.. // ///Example 3: Dynamic (Run-Time) Typing and Dispatch ///- - - - - - - - - - - - - - - - - - - - - - - - - // In this example, we introduce a class that is the 'bdlat' "dyanmic" type // category and show how its behavior is a generalization of what we have seen // for the "static" 'bdlat' types. // // First, we define a class, 'mine::MyDynamicType', that can hold one of two // value types: either a 'bsl::vector<char>' or a 'bsl::string'. //.. // namespace BloombergLP { // namespace mine { // // class MyDynamicType { // // This class can represent data in two forms: either a 'bsl::string' // // or as a 'bsl::vector' of 'char' values. // // // PRIVATE DATA MEMBERS // bsl::vector<char> d_vectorChar; // Note: Production code should use a // bsl::string d_string; // union of object buffers. // int d_selector; // 0 = vectorChar, 1 = string // // public: // // MANIPULATORS // void makeVectorChar() { d_selector = 0; } // void makeString() { d_selector = 1; } // // bsl::vector<char>& theVectorChar() // { assert(isVectorChar()); return d_vectorChar; } // bsl::string& theString() // { assert(isString()); return d_string; } // // // ACCESSORS // bool isVectorChar() const { return 0 == d_selector; } // bool isString() const { return 1 == d_selector; } // // const bsl::vector<char>& theVectorChar() const // { assert(isVectorChar()); return d_vectorChar; } // const bsl::string& theString() const // { assert(isString()); return d_string; } // // }; // // } // close package namespace // } // close enterprise namespace //.. // When acting as a vector this class is a 'bdlat' "array" type and when // holding a string, the class is a 'bdlat' "simple" type. Since this type can // be in two type categories (determined at runtime) this class is deemed a // "dynamic" class (for calculations at compile time). // // Then, to denote that this class is a dynamic type, we specialize the // 'bdlat_TypeCategoryDeclareDynamic' meta-function in the 'BloombergLP' // namespace: //.. // namespace BloombergLP { // // template <> // struct bdlat_TypeCategoryDeclareDynamic<mine::MyDynamicType> { // enum { VALUE = 1 }; // }; // // } // close enterprise namespace //.. // Now, we define bdlat_typeCategorySelect', and a suite of four functions, // 'bdlat_typeCategory(Manipulate|Access)(Array|Simple)', each overloaded for // our type, 'MyDynamicType'. //.. // namespace BloombergLP { // namespace mine { // // bdlat_TypeCategory::Value // bdlat_typeCategorySelect(const MyDynamicType& object) // { // if (object.isVectorChar()) { // return bdlat_TypeCategory::e_ARRAY_CATEGORY; // RETURN // } // else if (object.isString()) { // return bdlat_TypeCategory::e_SIMPLE_CATEGORY; // RETURN // } // // assert(!"Reached"); // // // Note that this 'return' is never reached and hence the returned // // value is immaterial. // // return bdlat_TypeCategory::e_SIMPLE_CATEGORY; // } // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateArray(MyDynamicType *object, // MANIPULATOR& manipulator) // { // if (object->isVectorChar()) { // return manipulator(&object->theVectorChar(), // bdlat_TypeCategory::Array()); // RETURN // } // // return manipulator(object, bslmf::Nil()); // } // // template <class MANIPULATOR> // int bdlat_typeCategoryManipulateSimple(MyDynamicType *object, // MANIPULATOR& manipulator) // { // if (object->isString()) { // return manipulator(&object->theString(), // bdlat_TypeCategory::Simple()); // RETURN // } // // return manipulator(object, bslmf::Nil()); // } // // template <class ACCESSOR> // int bdlat_typeCategoryAccessArray(const MyDynamicType& object, // ACCESSOR& accessor) // { // if (object.isVectorChar()) { // return accessor(object.theVectorChar(), // bdlat_TypeCategory::Array()); // RETURN // } // // return accessor(object, bslmf::Nil()); // } // // template <class ACCESSOR> // int bdlat_typeCategoryAccessSimple(const MyDynamicType& object, // ACCESSOR& accessor) // { // if (object.isString()) { // return accessor(object.theString(), // bdlat_TypeCategory::Simple()); // RETURN // } // // return accessor(object, bslmf::Nil()); // } // // } // close package namespace // } // close enterprise namespace //.. // Notice that the customization points were implemented for just the two type // categories that 'MyDynamicType' can achieve: "array" and "simple". // // Finally, we can see how the facilities we developed in {Example 1} and // {Example 2} behave when given a "dynamic" type; //.. // void runUsageExample3() // { //.. // We see that the 'Select' meta-function returns the expected value: //.. // assert(bdlat_TypeCategory::e_DYNAMIC_CATEGORY // == static_cast<bdlat_TypeCategory::Value>( // bdlat_TypeCategory::Select<mine::MyDynamicType>::e_SELECTION)); //.. // We create an object of our dynamic type and observe that the specialization // we created for printing the values (actually, for *not* printing the value // of) "dynamic" types is invoked: //.. // bsl::ostringstream oss; // mine::MyDynamicType object; // // mine::printCategoryAndValue(oss, object); // assert("DynamicType: Printing dynamic types requires extra work." // == oss.str()); // oss.str(""); //.. // We instruct object to behave as a vector and see that the 'bdlat' framework // treats the object as a member of the "array" category and the // 'PrintAccessor' we defined in {Example 2} treats 'object' as a member of the // "array" category: //.. // object.makeVectorChar(); // // assert(bdlat_TypeCategory::e_ARRAY_CATEGORY // == bdlat_TypeCategoryFunctions::select(object)); // // object.theVectorChar().push_back('H'); // object.theVectorChar().push_back('e'); // object.theVectorChar().push_back('l'); // object.theVectorChar().push_back('l'); // object.theVectorChar().push_back('o'); // // mine::PrintAccessor accessor(&oss); // int ret; // // ret = bdlat_TypeCategoryUtil::accessByCategory(object, accessor); // assert(0 == ret); // LOOP_ASSERT(oss.str(), "Array: \"Hello\"" == oss.str()); // oss.str(""); //.. // Lastly, we instruct 'object' to behave as a string and find that the 'bdlat' // framework now considers 'object' to be the "simple" category: //.. // object.makeString(); // // assert(bdlat_TypeCategory::e_SIMPLE_CATEGORY // == bdlat_TypeCategoryFunctions::select(object)); // // object.theString() = "World"; // // ret = bdlat_TypeCategoryUtil::accessByCategory(object, accessor); // assert(0 == ret); // assert("Simple: World" == oss.str()); // oss.str(""); // } //.. // Notice that the output of the accessor matches the state of the object, // reporting an "array" type when the object 'isVector' and a "simple" type // when the object 'isString'. #include <bdlscm_version.h> #include <bdlat_arrayfunctions.h> #include <bdlat_bdeatoverrides.h> #include <bdlat_choicefunctions.h> #include <bdlat_enumfunctions.h> #include <bdlat_nullablevaluefunctions.h> #include <bdlat_customizedtypefunctions.h> #include <bdlat_sequencefunctions.h> #include <bslmf_assert.h> #include <bslmf_conditional.h> #include <bslmf_issame.h> #include <bslmf_switch.h> #include <bsls_assert.h> namespace BloombergLP { // ======================================= // struct bdlat_TypeCategoryDeclareDynamic // ======================================= template <class TYPE> struct bdlat_TypeCategoryDeclareDynamic { // Types that have more than one of the following traits: // //: o 'bdlat_ArrayFunctions::IsArray<TYPE>::VALUE' //: o 'bdlat_ChoiceFunctions::IsChoice<TYPE>::VALUE' //: o 'bdlat_CustomizedTypeFunctions::IsCustomizedType<TYPE>::VALUE' //: o 'bdlat_EnumFunctions::IsEnumeration<TYPE>::VALUE' //: o 'bdlat_NullableValueFunctions::IsNullableValue<TYPE>::VALUE' //: o 'bdlat_SequenceFunctions::IsSequence<TYPE>::VALUE' // // are automatically recognized as dynamic types. However, there may exist // types that have *none* or only one of the above traits and still be // considered dynamic (e.g., "variants" of simple types etc). In order for // the 'bdlat' framework to treat these types as dynamic types, this // 'struct' must be specialized with a 'VALUE' of 1, and the // 'bdlat_TypeCategoryFunctions::select' function must be implemented, // along with the appropriate 'bdlat_TypeCategoryFunctions::manipulate*' // and 'bdlat_TypeCategoryFunctions::access*' functions. Inside these // 'manipulate*' and 'access*' functions, the dynamic object should expose // its real type. enum { VALUE = 0 }; }; // ========================= // struct bdlat_TypeCategory // ========================= struct bdlat_TypeCategory { // This struct provides the different category tags and also a // meta-function for selecting the tags based on the parameterized 'TYPE'. // TAGS struct DynamicType { }; // tag for dynamic types struct Array { }; // tag for arrays struct Choice { }; // tag for choices struct CustomizedType { }; // tag for customized types struct Enumeration { }; // tag for enumerations struct NullableValue { }; // tag for nullable values struct Sequence { }; // tag for sequences struct Simple { }; // tag for all other types // ENUMERATIONS enum Value { e_DYNAMIC_CATEGORY = 0, e_ARRAY_CATEGORY = 1, e_CHOICE_CATEGORY = 2, e_CUSTOMIZED_TYPE_CATEGORY = 3, e_ENUMERATION_CATEGORY = 4, e_NULLABLE_VALUE_CATEGORY = 5, e_SEQUENCE_CATEGORY = 6, e_SIMPLE_CATEGORY = 7 #ifndef BDE_OMIT_INTERNAL_DEPRECATED , DYNAMIC_CATEGORY = e_DYNAMIC_CATEGORY , ARRAY_CATEGORY = e_ARRAY_CATEGORY , CHOICE_CATEGORY = e_CHOICE_CATEGORY , CUSTOMIZED_TYPE_CATEGORY = e_CUSTOMIZED_TYPE_CATEGORY , ENUMERATION_CATEGORY = e_ENUMERATION_CATEGORY , NULLABLE_VALUE_CATEGORY = e_NULLABLE_VALUE_CATEGORY , SEQUENCE_CATEGORY = e_SEQUENCE_CATEGORY , SIMPLE_CATEGORY = e_SIMPLE_CATEGORY , BDEAT_DYNAMIC_CATEGORY = e_DYNAMIC_CATEGORY , BDEAT_ARRAY_CATEGORY = e_ARRAY_CATEGORY , BDEAT_CHOICE_CATEGORY = e_CHOICE_CATEGORY , BDEAT_CUSTOMIZED_TYPE_CATEGORY = e_CUSTOMIZED_TYPE_CATEGORY , BDEAT_ENUMERATION_CATEGORY = e_ENUMERATION_CATEGORY , BDEAT_NULLABLE_VALUE_CATEGORY = e_NULLABLE_VALUE_CATEGORY , BDEAT_SEQUENCE_CATEGORY = e_SEQUENCE_CATEGORY , BDEAT_SIMPLE_CATEGORY = e_SIMPLE_CATEGORY #endif // BDE_OMIT_INTERNAL_DEPRECATED }; // META-FUNCTION template <class TYPE> struct Select { // This meta-function contains a typedef 'Type' that specifies the // category tag for the parameterized 'TYPE'. Note that the runtime // analog to this meta-function is // 'bdlat_TypeCategoryFunctions::select' that returns the enumerator // corresponding to the 'bdlat' category. private: static const int k_IS_ARRAY = bdlat_ArrayFunctions::IsArray<TYPE>::VALUE; static const int k_IS_CHOICE = bdlat_ChoiceFunctions::IsChoice<TYPE>::VALUE; static const int k_IS_CUSTOMIZED_TYPE = bdlat_CustomizedTypeFunctions::IsCustomizedType<TYPE>::VALUE; static const int k_IS_ENUMERATION = bdlat_EnumFunctions::IsEnumeration<TYPE>::VALUE; static const int k_IS_NULLABLE_VALUE = bdlat_NullableValueFunctions::IsNullableValue<TYPE>::VALUE; static const int k_IS_SEQUENCE = bdlat_SequenceFunctions::IsSequence<TYPE>::VALUE; static const int k_NUM_CATEGORIES = k_IS_ARRAY + k_IS_CHOICE + k_IS_CUSTOMIZED_TYPE + k_IS_ENUMERATION + k_IS_NULLABLE_VALUE + k_IS_SEQUENCE; static const int k_IS_DYNAMIC = k_NUM_CATEGORIES > 1 || bdlat_TypeCategoryDeclareDynamic<TYPE>::VALUE; public: enum { e_SELECTION = k_IS_DYNAMIC ? e_DYNAMIC_CATEGORY : k_IS_ARRAY ? e_ARRAY_CATEGORY : k_IS_CHOICE ? e_CHOICE_CATEGORY : k_IS_CUSTOMIZED_TYPE ? e_CUSTOMIZED_TYPE_CATEGORY : k_IS_ENUMERATION ? e_ENUMERATION_CATEGORY : k_IS_NULLABLE_VALUE ? e_NULLABLE_VALUE_CATEGORY : k_IS_SEQUENCE ? e_SEQUENCE_CATEGORY : /* else */ e_SIMPLE_CATEGORY #ifndef BDE_OMIT_INTERNAL_DEPRECATED , SELECTION = e_SELECTION , BDEAT_SELECTION = e_SELECTION #endif // BDE_OMIT_INTERNAL_DEPRECATED }; typedef typename bslmf::Switch<e_SELECTION, DynamicType, Array, Choice, CustomizedType, Enumeration, NullableValue, Sequence, Simple>::Type Type; }; }; // ============================= // struct bdlat_TypeCategoryUtil // ============================= struct bdlat_TypeCategoryUtil { // This 'struct' contains utility functions that operate on 'bdlat' // compatible objects, implicitly dispatching to the action appropriate for // the 'bdlat' type category of the object. template <class TYPE, class MANIPULATOR> static int manipulateByCategory(TYPE *object, MANIPULATOR& manipulator); // Invoke one of the following functions, based on the result of // 'bdlat_TypeCategoryFunctions::select(object)': // //: o 'bdlat_TypeCategoryFunctions::manipulateArray' //: o 'bdlat_TypeCategoryFunctions::manipulateChoice' //: o 'bdlat_TypeCategoryFunctions::manipulateCustomizedType' //: o 'bdlat_TypeCategoryFunctions::manipulateEnumeration' //: o 'bdlat_TypeCategoryFunctions::manipulateNullableValue' //: o 'bdlat_TypeCategoryFunctions::manipulateSequence' //: o 'bdlat_TypeCategoryFunctions::manipulateSimple' // // where each function is invoked with the specified 'object' and // 'manipulator'. See {'MANIPULATOR' Functors} for the requirements on // 'manipulator'. Return the value returned by the invoked function. // The behavior is undefined unless the parameterized 'TYPE' supports // the type category returned by the call to the // 'bdlat_TypeCategoryFunctions::select' function. template <class TYPE, class ACCESSOR> static int accessByCategory(const TYPE& object, ACCESSOR& accessor); // Invoke one of the following functions, based on the result of // 'bdlat_TypeCategoryFunctions::select': // //: o 'bdlat_TypeCategoryFunctions::accessArray' //: o 'bdlat_TypeCategoryFunctions::accessChoice' //: o 'bdlat_TypeCategoryFunctions::accessCustomizedType' //: o 'bdlat_TypeCategoryFunctions::accessEnumeration' //: o 'bdlat_TypeCategoryFunctions::accessNullableValue' //: o 'bdlat_TypeCategoryFunctions::accessSequence' //: o 'bdlat_TypeCategoryFunctions::accessSimple' // // where each function is invoked with the specified 'object' and // 'accessor'. See {'ACCESSOR' Functors} for the requirements on // 'accessor'. Return the value returned by the invoked function. The // behavior is undefined unless the parameterized 'TYPE' supports the // type category returned by the call to the // 'bdlat_TypeCategoryFunctions::select' function. }; // ===================================== // namespace bdlat_TypeCategoryFunctions // ===================================== namespace bdlat_TypeCategoryFunctions { // This namespace contains function templates pertaining to type // categories. For each of the seven 'bdlat' type categories there are two // function templates: "maniuplate*Type*" and "access*Type". Additionally, // the 'select' function template returns the type (an enumerator) for a // given object. // MANIPULATORS template <class TYPE, class MANIPULATOR> int manipulateArray(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Array' // tag object (2nd argument). If 'object' is not a 'bdlat' "array" // type, pass a 'bslmf::Nil' tag object as the second argument. See // {'MANIPULATOR' Functors} for the requirements on 'manipulator'. template <class TYPE, class MANIPULATOR> int manipulateChoice(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Choice' // tag object (2nd argument). If 'object' is not a 'bdlat' "choice" // type, pass a 'bslmf::Nil' tag object as the second argument. See // {'MANIPULATOR' Functors} for the requirements on 'manipulator'. template <class TYPE, class MANIPULATOR> int manipulateCustomizedType(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::CustomizedType' tag object (2nd argument). If // 'object' is not a 'bdlat' "customized type" type, pass a // 'bslmf::Nil' tag object as the second argument. See {'MANIPULATOR' // Functors} for the requirements on 'manipulator'. template <class TYPE, class MANIPULATOR> int manipulateEnumeration(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::Enumeration' tag object (2nd argument). If // 'object' is not a 'bdlat' "enumeration" type, pass a 'bslmf::Nil' // tag object as the second argument. See {'MANIPULATOR' Functors} for // the requirements on 'manipulator'. template <class TYPE, class MANIPULATOR> int manipulateNullableValue(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::NullableValue' tag object (2nd argument). If // 'object' is not a 'bdlat' "nullable value" type, pass a 'bslmf::Nil' // tag object as the second argument. See {'MANIPULATOR' Functors} for // the requirements on 'manipulator'. template <class TYPE, class MANIPULATOR> int manipulateSequence(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::Sequence' tag object (2nd argument). If // 'object' is not a 'bdlat' "sequence" type, pass a 'bslmf::Nil' tag // object as the second argument. See {'MANIPULATOR' Functors} for the // requirements on 'manipulator'. template <class TYPE, class MANIPULATOR> int manipulateSimple(TYPE *object, MANIPULATOR& manipulator); // Return the result of invoking the specified 'manipulator' with the // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Simple' // tag object (2nd argument). If 'object' is not a 'bdlat' "simple" // type, pass a 'bslmf::Nil' tag object as the second argument. See // {'MANIPULATOR' Functors} for the requirements on 'manipulator'. // ACCESSORS template <class TYPE, class ACCESSOR> int accessArray(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Array' // tag object (2nd argument). If 'object' is not a 'bdlat' "array" // type, pass a 'bslmf::Nil' tag object as the second argument. See // {'ACCESSOR' Functors} for the requirements on 'accessor'. template <class TYPE, class ACCESSOR> int accessChoice(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Choice' // tag object (2nd argument). If 'object' is not a 'bdlat' "choice" // type, pass a 'bslmf::Nil' tag object as the second argument. See // {'ACCESSOR' Functors} for the requirements on 'accessor'. template <class TYPE, class ACCESSOR> int accessCustomizedType(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::CustomizedType' tag object (2nd argument). If // 'object' is not a 'bdlat' "customized type" type, pass a // 'bslmf::Nil' tag object as the second argument. See {'ACCESSOR' // Functors} for the requirements on 'accessor'. template <class TYPE, class ACCESSOR> int accessEnumeration(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::Enumeration' tag object (2nd argument). If // 'object' is not a 'bdlat' "enumeration type" type, pass a // 'bslmf::Nil' tag object as the second argument. See {'ACCESSOR' // Functors} for the requirements on 'accessor'. template <class TYPE, class ACCESSOR> int accessNullableValue(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::NullableValue' tag object (2nd argument). If // 'object' is not a 'bdlat' "nullable value" type, pass a 'bslmf::Nil' // tag object as the second argument. See {'ACCESSOR' Functors} for // the requirements on 'accessor'. template <class TYPE, class ACCESSOR> int accessSequence(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a // 'bdlat_TypeCategory::Sequence' tag object (2nd argument). If // 'object' is not a 'bdlat' "sequence" type, pass a 'bslmf::Nil' tag // object as the second argument. See {'ACCESSOR' Functors} for the // requirements on 'accessor'. template <class TYPE, class ACCESSOR> int accessSimple(const TYPE& object, ACCESSOR& accessor); // Return the result of invoking the specified 'accessor' with the // specified 'object' (1st argument) and a 'bdlat_TypeCategory::Simple' // tag object (2nd argument). If 'object' is not a 'bdlat' "simple" // type, pass a 'bslmf::Nil' tag object as the second argument. See // {'ACCESSOR' Functors} for the requirements on 'accessor'. template <class TYPE> bdlat_TypeCategory::Value select(const TYPE& object); // Return the *runtime* type category for the specified 'object'. The // value returned is never 'bdlat_TypeCategory::e_DYNAMIC_CATEGORY' (as // "dynamic" is a compile-time distinction). Note that the compile // time analog to this function (template) is // 'bdlat_TypeCategory::Select', a meta-function that defines a type // corresponding to the category tag class of 'TYPE'. // OVERLOADABLE FUNCTIONS // The following functions should be overloaded for other types (in their // respective namespaces). The following functions are the default // implementations (for 'bas_codegen.pl'-generated types). Do *not* call // these functions directly. Use the functions above instead. // MANIPULATORS template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateArray(TYPE *object, MANIPULATOR& manipulator); template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateChoice(TYPE *object, MANIPULATOR& manipulator); template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateCustomizedType(TYPE *object, MANIPULATOR& manipulator); template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateEnumeration(TYPE *object, MANIPULATOR& manipulator); template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateNullableValue(TYPE *object, MANIPULATOR& manipulator); template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateSequence(TYPE *object, MANIPULATOR& manipulator); template <class TYPE, class MANIPULATOR> int bdlat_typeCategoryManipulateSimple(TYPE *object, MANIPULATOR& manipulator); // ACCESSORS template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessArray(const TYPE& object, ACCESSOR& accessor); template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessChoice(const TYPE& object, ACCESSOR& accessor); template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessCustomizedType(const TYPE& object, ACCESSOR& accessor); template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessEnumeration(const TYPE& object, ACCESSOR& accessor); template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessNullableValue(const TYPE& object, ACCESSOR& accessor); template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessSequence(const TYPE& object, ACCESSOR& accessor); template <class TYPE, class ACCESSOR> int bdlat_typeCategoryAccessSimple(const TYPE& object, ACCESSOR& accessor); template <class TYPE> bdlat_TypeCategory::Value bdlat_typeCategorySelect(const TYPE& object); } // close namespace bdlat_TypeCategoryFunctions // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // ----------------------------- // struct bdlat_TypeCategoryUtil // ----------------------------- template <class TYPE, class MANIPULATOR> int bdlat_TypeCategoryUtil::manipulateByCategory(TYPE *object, MANIPULATOR& manipulator) { using namespace bdlat_TypeCategoryFunctions; switch (select(*object)) { case bdlat_TypeCategory::e_DYNAMIC_CATEGORY: { BSLS_ASSERT_SAFE("'select' must not return 'DYNAMIC_CATEGORY'." && 0); return -1; // RETURN } case bdlat_TypeCategory::e_ARRAY_CATEGORY: { return manipulateArray(object, manipulator); // RETURN } case bdlat_TypeCategory::e_CHOICE_CATEGORY: { return manipulateChoice(object, manipulator); // RETURN } case bdlat_TypeCategory::e_CUSTOMIZED_TYPE_CATEGORY: { return manipulateCustomizedType(object, manipulator); // RETURN } case bdlat_TypeCategory::e_ENUMERATION_CATEGORY: { return manipulateEnumeration(object, manipulator); // RETURN } case bdlat_TypeCategory::e_NULLABLE_VALUE_CATEGORY: { return manipulateNullableValue(object, manipulator); // RETURN } case bdlat_TypeCategory::e_SEQUENCE_CATEGORY: { return manipulateSequence(object, manipulator); // RETURN } case bdlat_TypeCategory::e_SIMPLE_CATEGORY: { return manipulateSimple(object, manipulator); // RETURN } } // An assertion here indicates that the 'select' function returned an // invalid value. BSLS_ASSERT_SAFE(0); return -1; } template <class TYPE, class ACCESSOR> int bdlat_TypeCategoryUtil::accessByCategory(const TYPE& object, ACCESSOR& accessor) { using namespace bdlat_TypeCategoryFunctions; switch (select(object)) { case bdlat_TypeCategory::e_DYNAMIC_CATEGORY: { BSLS_ASSERT_SAFE("'select' must not return 'DYNAMIC_CATEGORY'." && 0); return -1; // RETURN } case bdlat_TypeCategory::e_ARRAY_CATEGORY: { return accessArray(object, accessor); // RETURN } case bdlat_TypeCategory::e_CHOICE_CATEGORY: { return accessChoice(object, accessor); // RETURN } case bdlat_TypeCategory::e_CUSTOMIZED_TYPE_CATEGORY: { return accessCustomizedType(object, accessor); // RETURN } case bdlat_TypeCategory::e_ENUMERATION_CATEGORY: { return accessEnumeration(object, accessor); // RETURN } case bdlat_TypeCategory::e_NULLABLE_VALUE_CATEGORY: { return accessNullableValue(object, accessor); // RETURN } case bdlat_TypeCategory::e_SEQUENCE_CATEGORY: { return accessSequence(object, accessor); // RETURN } case bdlat_TypeCategory::e_SIMPLE_CATEGORY: { return accessSimple(object, accessor); // RETURN } } // An assertion here indicates that the 'select' function returned an // invalid value. BSLS_ASSERT_SAFE(0); return -1; } // ------------------------------------- // namespace bdlat_TypeCategoryFunctions // ------------------------------------- // MANIPULATORS template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateArray(TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateArray(object, manipulator); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateChoice(TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateChoice(object, manipulator); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateCustomizedType( TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateCustomizedType(object, manipulator); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateEnumeration( TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateEnumeration(object, manipulator); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateNullableValue( TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateNullableValue(object, manipulator); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateSequence(TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateSequence(object, manipulator); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::manipulateSimple(TYPE *object, MANIPULATOR& manipulator) { return bdlat_typeCategoryManipulateSimple(object, manipulator); } // ACCESSORS template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessArray(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessArray(object, accessor); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessChoice(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessChoice(object, accessor); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessCustomizedType(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessCustomizedType(object, accessor); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessEnumeration(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessEnumeration(object, accessor); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessNullableValue(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessNullableValue(object, accessor); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessSequence(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessSequence(object, accessor); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::accessSimple(const TYPE& object, ACCESSOR& accessor) { return bdlat_typeCategoryAccessSimple(object, accessor); } template <class TYPE> inline bdlat_TypeCategory::Value bdlat_TypeCategoryFunctions::select( const TYPE& object) { return bdlat_typeCategorySelect(object); } // -------------------------------------------------------------- // namespace bdlat_TypeCategoryFunctions (OVERLOADABLE FUNCTIONS) // -------------------------------------------------------------- // MANIPULATORS template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateArray( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional<bdlat_ArrayFunctions::IsArray<TYPE>::VALUE, bdlat_TypeCategory::Array, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateChoice( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional<bdlat_ChoiceFunctions::IsChoice<TYPE>::VALUE, bdlat_TypeCategory::Choice, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateCustomizedType( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional< bdlat_CustomizedTypeFunctions::IsCustomizedType<TYPE>::VALUE, bdlat_TypeCategory::CustomizedType, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateEnumeration( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional< bdlat_EnumFunctions::IsEnumeration<TYPE>::VALUE, bdlat_TypeCategory::Enumeration, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateNullableValue( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional< bdlat_NullableValueFunctions::IsNullableValue<TYPE>::VALUE, bdlat_TypeCategory::NullableValue, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateSequence( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional< bdlat_SequenceFunctions::IsSequence<TYPE>::VALUE, bdlat_TypeCategory::Sequence, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } template <class TYPE, class MANIPULATOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryManipulateSimple( TYPE *object, MANIPULATOR& manipulator) { typedef typename bsl::conditional< (int)bdlat_TypeCategory::Select<TYPE>::e_SELECTION == (int)bdlat_TypeCategory::e_SIMPLE_CATEGORY, bdlat_TypeCategory::Simple, bslmf::Nil>::type Tag; return manipulator(object, Tag()); } // ACCESSORS template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessArray( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< bdlat_ArrayFunctions::IsArray<TYPE>::VALUE, bdlat_TypeCategory::Array, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessChoice( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< bdlat_ChoiceFunctions::IsChoice<TYPE>::VALUE, bdlat_TypeCategory::Choice, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessCustomizedType( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< bdlat_CustomizedTypeFunctions::IsCustomizedType<TYPE>::VALUE, bdlat_TypeCategory::CustomizedType, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessEnumeration( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< bdlat_EnumFunctions::IsEnumeration<TYPE>::VALUE, bdlat_TypeCategory::Enumeration, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessNullableValue( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< bdlat_NullableValueFunctions::IsNullableValue<TYPE>::VALUE, bdlat_TypeCategory::NullableValue, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessSequence( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< bdlat_SequenceFunctions::IsSequence<TYPE>::VALUE, bdlat_TypeCategory::Sequence, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE, class ACCESSOR> inline int bdlat_TypeCategoryFunctions::bdlat_typeCategoryAccessSimple( const TYPE& object, ACCESSOR& accessor) { typedef typename bsl::conditional< (int)bdlat_TypeCategory::Select<TYPE>::e_SELECTION == (int)bdlat_TypeCategory::e_SIMPLE_CATEGORY, bdlat_TypeCategory::Simple, bslmf::Nil>::type Tag; return accessor(object, Tag()); } template <class TYPE> inline bdlat_TypeCategory::Value bdlat_TypeCategoryFunctions::bdlat_typeCategorySelect(const TYPE&) { enum { e_SELECTION = bdlat_TypeCategory::Select<TYPE>::e_SELECTION }; // An assertion below indicates that 'TYPE' is a dynamic type, but does not // overload this 'select' function. Dynamic types *must* overload this // 'select' function to implement the logic that determines the *runtime* // type category. BSLMF_ASSERT(bdlat_TypeCategory::e_DYNAMIC_CATEGORY != (bdlat_TypeCategory::Value)e_SELECTION); return (bdlat_TypeCategory::Value)e_SELECTION; } } // 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 ----------------------------------