// bdlat_symbolicconverter.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_SYMBOLICCONVERTER #define INCLUDED_BDLAT_SYMBOLICCONVERTER #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a utility for convert types with matching member symbols. // //@CLASSES: // bdlat_SymbolicConverter: symbolic converter utility // //@SEE_ALSO: // //@DESCRIPTION: The 'bdlat_SymbolicConverter' utility provided by this // component defines a single parameterized function 'convert'. The 'convert' // function takes two arguments: a destination and a source object. The // destination and source objects may be of different types. // // Each type can fall into one of the following categories: //.. // Category Reference // -------- --------- // Sequence bdlat_sequencefunctions // Choice bdlat_choicefunctions // Array bdlat_arrayfunctions // Enumeration bdlat_enumfunctions // NullableValue bdlat_nullablevaluefunctions // CustomizedType bdlat_customizedtypefunctions // Simple basic C++ fundamental types & other value-semantic types //.. // The 'bdlat_SymbolicConverter' utility converts from one type to another // using the following criteria: //.. // Destination Category Source Category Comments // -------------------- --------------- -------- // Sequence Sequence The conversion will fail if each // attribute in the set of attributes // from the source does not have a // corresponding attribute (with the // same name) in the destination. The // conversion will also fail if any // attributes from the source fail to // convert to the corresponding // attribute in the destination. Any // attribute in the destination that // does not have a corresponding // attribute in the source will be set // to its default value. // // Choice Choice The conversion will fail if the // destination does not have a // selection with the same name as the // current selection in the source. // The conversion will also fail if // the selection from the source fails // to convert to the corresponding // selection in the destination. If // nothing is selected in the source, // then the destination will be reset. // // Array Array The conversion will fail if the // elements in the source fail to // convert to the elements in the // destination. Upon completion, the // destination array will contain the // same number of elements as the // source array. // // Enumeration Enumeration The conversion will fail if the // destination does not have a string // value that is identical to the // string value of the source. // // Enumeration char/short/int The conversion will fail if the // destination does not have an // enumerator with the numeric value // of the source. // // char/short/int Enumeration The conversion will fail if the // numeric value of the enumeration is // outside the bounds of the // destination type. // // Enumeration bsl::string The conversion will fail if the // destination does not have an // enumerator with the symbolic string // name of the source. // // bsl::string Enumeration This conversion always succeeds. // // NullableValue NullableValue The conversion will fail if the // source has a value that fails to // convert to the destination value. // If the source is null, then the // destination is nulled. // // NullableValue AnyType The conversion will fail if the // source fails to convert to the // destination value. // // AnyType NullableValue The conversion will fail if the // source is not null and the value in // the source fails to convert to the // destination. If the source is // null, then the destination will // be set to its default value. // // CustomizedType CustomizedType The conversion will fail if the // base value in the source fails to // convert to the base value in the // destination and the base value is // able to convert to the customized // value. // // CustomizedType AnyType The conversion will fail if the // source fails to convert to the base // value in the destination and the // base value is able to convert to // the customized value. // // AnyType CustomizedType The conversion will fail if the // base value in the source fails to // convert to the destination. // // SimpleType SimpleType The conversion will fail if there // is no accessible compile-time // assignment operator from the // destination to the source. This is // determined using // 'bslmf_isconvertible'. //.. // Any other combination of destination and source categories will fail to // convert. // ///Usage ///----- // The following snippets of code illustrate the usage of this component. This // component can be used with types supported by the 'bdlat' framework. In // particular, types generated by the 'bas_codegen.pl' tool can be used. For // example, suppose we have the following XML schema inside a file called // 'xsdfile.xsd': //.. // <?xml version='1.0' encoding='UTF-8'?> // <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema' // xmlns:bdem='http://bloomberg.com/schemas/bdem' // elementFormDefault='unqualified'> // // <xs:complexType name='Employee'> // <xs:sequence> // <xs:element name='Name' type='string'/> // <xs:element name='Dept' type='string'/> // <xs:element name='Age' type='int'/> // <xs:element name='Salary' type='float'/> // </xs:sequence> // </xs:complexType> // // <xs:complexType name='Trainee'> // <xs:sequence> // <xs:element name='Name' type='string'/> // <xs:element name='Dept' type='string'/> // <xs:element name='Age' type='int'/> // </xs:sequence> // </xs:complexType> // // </xs:schema> //.. // Using the 'bas_codegen.pl' tool, we can generate C++ classes for this // schema: //.. // $ bas_codegen.pl -g h -g cpp -p test xsdfile.xsd //.. // This tool will generate the header and implementation files for the // 'test_employee' and 'test_trainee' components in the current directory. // // Now suppose we want to create a 'hireTrainee' function, that converts a // trainee to an employee. Such a function could be written as follows: //.. // #include <test_employee.h> // #include <test_trainee.h> // // #include <bdlat_symbolicconverter.h> // // using namespace BloombergLP; // // int hireTrainee(test::Employee *result, // const test::Trainee& trainee, // float salary) // { // int retCode = bdlat_SymbolicConverter::convert(result, trainee); // // result->salary() = salary; // // return retCode; // } //.. // The 'hireTrainee' function can be used as follows: //.. // void usageExample() // { // test::Trainee trainee; // // trainee.name() = "Bob"; // trainee.dept() = "RnD"; // trainee.age() = 24; // // test::Employee employee; // // int result = hireTrainee(&employee, trainee, 20000.00f); // // assert(0 == result); // assert("Bob" == employee.name()); // assert("RnD" == employee.dept()); // assert(24 == employee.age()); // assert(20000.00f == employee.salary()); // } //.. #include <bdlscm_version.h> #include <bdlat_arrayfunctions.h> #include <bdlat_bdeatoverrides.h> #include <bdlat_choicefunctions.h> #include <bdlat_customizedtypefunctions.h> #include <bdlat_enumfunctions.h> #include <bdlat_nullablevaluefunctions.h> #include <bdlat_sequencefunctions.h> #include <bdlat_typecategory.h> #include <bdlat_valuetypefunctions.h> #include <bdlb_printmethods.h> #include <bslmf_switch.h> #include <bsls_assert.h> #include <bsls_review.h> #include <bsl_ostream.h> #include <bsl_string.h> namespace BloombergLP { // ============================== // struct bdlat_SymbolicConverter // ============================== struct bdlat_SymbolicConverter { // This utility contains a single 'convert' function that converts a value // from one type to another compatible type. template <class LHS_TYPE, class RHS_TYPE> static int convert(LHS_TYPE *lhs, const RHS_TYPE &rhs); template <class LHS_TYPE, class RHS_TYPE> static int convert(LHS_TYPE *lhs, const RHS_TYPE &rhs, bsl::ostream &errorStream); // Convert the value of the specified 'rhs' object to the specified // (modifiable) 'lhs' object. Optionally specify an 'errorStream' to // print error messages. Return 0 on success and a non-zero value // otherwise. The supported conversions are described in the // 'bdlat_symbolicconverter' component-level documentation. }; // --- Anything below this line is implementation specific. Do not use. ---- // ================================= // class bdlat_SymbolicConverter_Imp // ================================= class bdlat_SymbolicConverter_Imp { // This class contains implementation functions for this component. // PRIVATE DATA MEMBERS bsl::ostream *d_errorStream_p; // held, not owned public: // IMPLEMENTATION MANIPULATORS template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Sequence lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Sequence rhsCategory); // Convert to sequence from sequence. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Choice lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Choice rhsCategory); // Convert to choice from choice. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Array lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Array rhsCategory); // Convert to array from array. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Enumeration lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Enumeration rhsCategory); // Convert to enum from enum. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Enumeration lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Simple rhsCategory); // Convert to enum from simple type. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Simple lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Enumeration rhsCategory); // Convert to simple type from enum. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::NullableValue lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::NullableValue rhsCategory); // Convert to nullable from nullable. template <class LHS_TYPE, class RHS_TYPE, class RHS_CATEGORY> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::NullableValue lhsCategory, const RHS_TYPE& rhs, RHS_CATEGORY rhsCategory); // Convert to nullable from non-nullable. template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE> int convert(LHS_TYPE *lhs, LHS_CATEGORY lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::NullableValue rhsCategory); // Convert to non-nullable from nullable. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::CustomizedType lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::NullableValue rhsCategory); // Convert to customized type from nullable. Note that this overload // is required to resolve ambiguities when there are nullable and // customized types in the same sequence. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::CustomizedType lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::CustomizedType rhsCategory); // Convert to customized from customized. template <class LHS_TYPE, class RHS_TYPE, class RHS_CATEGORY> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::CustomizedType lhsCategory, const RHS_TYPE& rhs, RHS_CATEGORY rhsCategory); // Convert to customized from non-customized. template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE> int convert(LHS_TYPE *lhs, LHS_CATEGORY lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::CustomizedType rhsCategory); // Convert to non-customized from customized. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::NullableValue lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::CustomizedType rhsCategory); // Convert to nullable from customized. Note that this overload is // required to resolve ambiguities when there are nullable and // customized types in the same sequence. template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, bdlat_TypeCategory::Simple lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::Simple rhsCategory); // Convert to simple from simple of the same type. Note that this just // evaluates to an assignment using the assignment operator. template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE, class RHS_CATEGORY> int convert(LHS_TYPE *lhs, LHS_CATEGORY lhsCategory, const RHS_TYPE& rhs, RHS_CATEGORY rhsCategory); // No match found. This function does nothing, it just returns a // FAILURE code (to be used to detect type-mismatch at runtime). template <class LHS_TYPE, class RHS_TYPE> int resolveDynamicTypes(LHS_TYPE *lhs, bdlat_TypeCategory::DynamicType lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::DynamicType rhsCategory); template <class LHS_TYPE, class RHS_TYPE, class RHS_CATEGORY> int resolveDynamicTypes(LHS_TYPE *lhs, bdlat_TypeCategory::DynamicType lhsCategory, const RHS_TYPE& rhs, RHS_CATEGORY rhsCategory); template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE> int resolveDynamicTypes(LHS_TYPE *lhs, LHS_CATEGORY lhsCategory, const RHS_TYPE& rhs, bdlat_TypeCategory::DynamicType rhsCategory); template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE, class RHS_CATEGORY> int resolveDynamicTypes(LHS_TYPE *lhs, LHS_CATEGORY lhsCategory, const RHS_TYPE& rhs, RHS_CATEGORY rhsCategory); // Resolve dynamic types. private: // NOT IMPLEMENTED bdlat_SymbolicConverter_Imp(const bdlat_SymbolicConverter_Imp&); bdlat_SymbolicConverter_Imp& operator=(const bdlat_SymbolicConverter_Imp&); public: // CREATORS bdlat_SymbolicConverter_Imp(bsl::ostream *errorStream); // Create the imp object. // ~bdlat_SymbolicConverter_Imp(); // Destroy this object. Note that this trivial destructor is generated // by the compiler. // MANIPULATORS template <class LHS_TYPE, class RHS_TYPE> int convert(LHS_TYPE *lhs, const RHS_TYPE& rhs); // Implementation for convert function. bsl::ostream& errorStream(); // Return a reference to the error stream. }; // ===================================================== // class bdlat_SymbolicConverter_StoreValue<LVALUE_TYPE> // ===================================================== template <class LVALUE_TYPE> class bdlat_SymbolicConverter_StoreValue { // This visitor assigns the value of the visited member to // 'd_destination_p'. // PRIVATE DATA MEMBERS LVALUE_TYPE *d_destination_p; // held, not owned bdlat_SymbolicConverter_Imp *d_imp_p; // held, not owned public: // CREATORS explicit bdlat_SymbolicConverter_StoreValue( LVALUE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp); // ACCESSORS template <class RVALUE_TYPE, class INFO_TYPE> int operator()(const RVALUE_TYPE& object, const INFO_TYPE&) const; // Assign the specified 'object' to '*d_lValue_p'. template <class RVALUE_TYPE> int operator()(const RVALUE_TYPE& object) const; // Assign the specified 'object' to '*d_lValue_p'. }; // ==================================================== // class bdlat_SymbolicConverter_LoadValue<RVALUE_TYPE> // ==================================================== template <class RVALUE_TYPE> class bdlat_SymbolicConverter_LoadValue { // This visitor assigns 'd_value' to the visited member. // PRIVATE DATA MEMBERS bdlat_SymbolicConverter_Imp *d_imp_p; // held, not owned const RVALUE_TYPE& d_value; // held, not owned public: // CREATORS explicit bdlat_SymbolicConverter_LoadValue( const RVALUE_TYPE& value, bdlat_SymbolicConverter_Imp *imp); // ACCESSORS template <class LVALUE_TYPE, class INFO_TYPE> int operator()(LVALUE_TYPE *object, const INFO_TYPE&) const; // Assign 'd_value' to the specified '*object'. template <class LVALUE_TYPE> int operator()(LVALUE_TYPE *object) const; // Assign 'd_value' to the specified '*object'. }; // ============================================================ // class bdlat_SymbolicConverter_StoreInSequence<SEQUENCE_TYPE> // ============================================================ template <class SEQUENCE_TYPE> class bdlat_SymbolicConverter_StoreInSequence { // This visitor is used when assigning to a sequence. It will visit each // member from the source object. Each time a member is visited, it will // use the 'LoadValue' visitor template to visit the member with the same // name in the destination sequence. This will cause the value of the // member in the source object to be assigned to the member (with the same // name) of the destination sequence object. // PRIVATE DATA MEMBERS SEQUENCE_TYPE *d_destination_p; // held, not owned bdlat_SymbolicConverter_Imp *d_imp_p; // held, not owned public: // CREATORS explicit bdlat_SymbolicConverter_StoreInSequence( SEQUENCE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp); // ACCESSORS template <class SOURCE_MEMBER_TYPE, class INFO_TYPE> int operator()(const SOURCE_MEMBER_TYPE& sourceMember, const INFO_TYPE& info) const; }; // ======================================================== // class bdlat_SymbolicConverter_StoreInChoice<CHOICE_TYPE> // ======================================================== template <class CHOICE_TYPE> class bdlat_SymbolicConverter_StoreInChoice { // Similar to 'StoreInSequence' but this is for choice. // PRIVATE DATA MEMBERS CHOICE_TYPE *d_destination_p; // held, not owned bdlat_SymbolicConverter_Imp *d_imp_p; // held, not owned public: // CREATORS explicit bdlat_SymbolicConverter_StoreInChoice( CHOICE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp); // ACCESSORS template <class SOURCE_MEMBER_TYPE, class INFO_TYPE> int operator()(const SOURCE_MEMBER_TYPE& sourceMember, const INFO_TYPE& info) const; }; // ============================================================= // class bdlat_SymbolicConverter_StoreInArrayElement<ARRAY_TYPE> // ============================================================= template <class ARRAY_TYPE> class bdlat_SymbolicConverter_StoreInArrayElement { // Assign the value of the visited object to the 'd_index'th element inside // 'd_array_p'. // PRIVATE DATA MEMBERS ARRAY_TYPE *d_array_p; // held, not owned bdlat_SymbolicConverter_Imp *d_imp_p; // held, not owned int d_index; // element index to assign to public: // CREATORS bdlat_SymbolicConverter_StoreInArrayElement( ARRAY_TYPE *array, int index, bdlat_SymbolicConverter_Imp *imp); // ACCESSORS template <class SOURCE_ELEMENT_TYPE> int operator()(const SOURCE_ELEMENT_TYPE& sourceElement) const; }; // ============================================================ // class bdlat_SymbolicConverter_StoreInNullable<NULLABLE_TYPE> // ============================================================ template <class NULLABLE_TYPE> class bdlat_SymbolicConverter_StoreInNullable { // Similar to 'StoreInSequence' but this is for nullable. // PRIVATE DATA MEMBERS NULLABLE_TYPE *d_destination_p; // held, not owned bdlat_SymbolicConverter_Imp *d_imp_p; // held, not owned public: // CREATORS explicit bdlat_SymbolicConverter_StoreInNullable( NULLABLE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp); // ACCESSORS template <class VALUE_TYPE> int operator()(const VALUE_TYPE& value) const; }; // ============================================================================ // PROXY CLASSES // ============================================================================ // ========================================================= // struct bdlat_SymbolicConverter_Imp_resolveDynamicRhsProxy // ========================================================= template <class LHS_TYPE, class LHS_CATEGORY> struct bdlat_SymbolicConverter_Imp_resolveDynamicRhsProxy { // Component-private struct. Do not use. // DATA MEMBERS bdlat_SymbolicConverter_Imp *d_instance_p; LHS_TYPE *d_lhs_p; // CREATORS // Creators have been omitted to allow simple static initialization of this // struct. // FUNCTIONS template <class TYPE> inline int operator()(const TYPE&, bslmf::Nil) { BSLS_ASSERT_SAFE(0); return -2; } template <class TYPE, class ANY_CATEGORY> inline int operator()(const TYPE& object, ANY_CATEGORY category) { return d_instance_p->resolveDynamicTypes(d_lhs_p, LHS_CATEGORY(), object, category); } }; // ========================================================= // struct bdlat_SymbolicConverter_Imp_resolveDynamicLhsProxy // ========================================================= template <class RHS_TYPE, class RHS_CATEGORY> struct bdlat_SymbolicConverter_Imp_resolveDynamicLhsProxy { // Component-private struct. Do not use. // DATA MEMBERS bdlat_SymbolicConverter_Imp *d_instance_p; const RHS_TYPE *d_rhs_p; // CREATORS // Creators have been omitted to allow simple static initialization of this // struct. // FUNCTIONS template <class TYPE> inline int operator()(TYPE *, bslmf::Nil) { BSLS_ASSERT_SAFE(0); return -3; } template <class TYPE, class ANY_CATEGORY> inline int operator()(TYPE *object, ANY_CATEGORY category) { return d_instance_p->resolveDynamicTypes(object, category, *d_rhs_p, RHS_CATEGORY()); } }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // --------------------------------- // class bdlat_SymbolicConverter_Imp // --------------------------------- // PRIVATE MANIPULATORS template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Sequence, const RHS_TYPE& rhs, bdlat_TypeCategory::Sequence) { bdlat_SymbolicConverter_StoreInSequence<LHS_TYPE> storeInLhs(lhs, this); return bdlat_SequenceFunctions::accessAttributes(rhs, storeInLhs); } template <class LHS_TYPE, class RHS_TYPE> int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Choice, const RHS_TYPE& rhs, bdlat_TypeCategory::Choice) { enum { k_SUCCESS = 0 }; bdlat_SymbolicConverter_StoreInChoice<LHS_TYPE> storeInLhs(lhs, this); if (bdlat_ChoiceFunctions::k_UNDEFINED_SELECTION_ID == bdlat_ChoiceFunctions::selectionId(rhs)) { bdlat_ValueTypeFunctions::reset(lhs); return k_SUCCESS; // RETURN } return bdlat_ChoiceFunctions::accessSelection(rhs, storeInLhs); } template <class LHS_TYPE, class RHS_TYPE> int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Array, const RHS_TYPE& rhs, bdlat_TypeCategory::Array) { enum { k_SUCCESS = 0, k_FAILURE = -4 }; const int size = static_cast<int>(bdlat_ArrayFunctions::size(rhs)); bdlat_ArrayFunctions::resize(lhs, size); for (int i = 0; i < size; ++i) { bdlat_SymbolicConverter_StoreInArrayElement<LHS_TYPE> storeInLhs(lhs, i, this); if (0 != bdlat_ArrayFunctions::accessElement(rhs, storeInLhs, i)) { return k_FAILURE; // RETURN } } return k_SUCCESS; } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Enumeration, const RHS_TYPE& rhs, bdlat_TypeCategory::Enumeration) { bsl::string str; bdlat_EnumFunctions::toString(&str, rhs); return bdlat_EnumFunctions::fromString(lhs, str.data(), static_cast<int>(str.length())); } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Enumeration, const RHS_TYPE& rhs, bdlat_TypeCategory::Simple) { return bdlat_ValueTypeFunctions::assign(lhs, rhs); } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Simple, const RHS_TYPE& rhs, bdlat_TypeCategory::Enumeration) { return bdlat_ValueTypeFunctions::assign(lhs, rhs); } template <class LHS_TYPE, class RHS_TYPE> int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, bdlat_TypeCategory::NullableValue, const RHS_TYPE& rhs, bdlat_TypeCategory::NullableValue) { enum { k_SUCCESS = 0 }; if (bdlat_NullableValueFunctions::isNull(rhs)) { bdlat_ValueTypeFunctions::reset(lhs); return k_SUCCESS; // RETURN } bdlat_SymbolicConverter_StoreInNullable<LHS_TYPE> storeInLhs(lhs, this); return bdlat_NullableValueFunctions::accessValue(rhs, storeInLhs); } template <class LHS_TYPE, class RHS_TYPE, class RHS_CATEGORY> inline int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, bdlat_TypeCategory::NullableValue, const RHS_TYPE& rhs, RHS_CATEGORY) { bdlat_SymbolicConverter_StoreInNullable<LHS_TYPE> storeInLhs(lhs, this); return storeInLhs(rhs); } template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE> int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, LHS_CATEGORY, const RHS_TYPE& rhs, bdlat_TypeCategory::NullableValue) { enum { k_SUCCESS = 0 }; if (bdlat_NullableValueFunctions::isNull(rhs)) { // ignore the value and let '*lhs' contain its *default* value return k_SUCCESS; // RETURN } bdlat_SymbolicConverter_StoreValue<LHS_TYPE> storeIntoLhs(lhs, this); return bdlat_NullableValueFunctions::accessValue(rhs, storeIntoLhs); } template <class LHS_TYPE, class RHS_TYPE> int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, bdlat_TypeCategory::CustomizedType, const RHS_TYPE& rhs, bdlat_TypeCategory::NullableValue) { enum { k_SUCCESS = 0 }; if (bdlat_NullableValueFunctions::isNull(rhs)) { // ignore the value and let '*lhs' contain its *default* value return k_SUCCESS; // RETURN } bdlat_SymbolicConverter_StoreValue<LHS_TYPE> storeIntoLhs(lhs, this); return bdlat_NullableValueFunctions::accessValue(rhs, storeIntoLhs); } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, bdlat_TypeCategory::CustomizedType, const RHS_TYPE& rhs, bdlat_TypeCategory::CustomizedType) { return convert(lhs, bdlat_CustomizedTypeFunctions::convertToBaseType(rhs)); } template <class LHS_TYPE, class RHS_TYPE, class RHS_CATEGORY> int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, bdlat_TypeCategory::CustomizedType, const RHS_TYPE& rhs, RHS_CATEGORY) { enum { k_FAILURE = -5 }; typedef typename bdlat_CustomizedTypeFunctions::BaseType<LHS_TYPE>::Type LhsBaseType; LhsBaseType lhsBaseValue; if (0 != convert(&lhsBaseValue, rhs)) { return k_FAILURE; // RETURN } return bdlat_CustomizedTypeFunctions::convertFromBaseType(lhs, lhsBaseValue); } template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, LHS_CATEGORY, const RHS_TYPE& rhs, bdlat_TypeCategory::CustomizedType) { return convert(lhs, bdlat_CustomizedTypeFunctions::convertToBaseType(rhs)); } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert( LHS_TYPE *lhs, bdlat_TypeCategory::NullableValue, const RHS_TYPE& rhs, bdlat_TypeCategory::CustomizedType) { return convert(lhs, bdlat_CustomizedTypeFunctions::convertToBaseType(rhs)); } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, bdlat_TypeCategory::Simple, const RHS_TYPE& rhs, bdlat_TypeCategory::Simple) { return bdlat_ValueTypeFunctions::assign(lhs, rhs); } template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE, class RHS_CATEGORY> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *, LHS_CATEGORY, const RHS_TYPE&, RHS_CATEGORY) { enum { k_FAILURE = -6 }; return k_FAILURE; } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::resolveDynamicTypes( LHS_TYPE *lhs, bdlat_TypeCategory::DynamicType, const RHS_TYPE& rhs, bdlat_TypeCategory::DynamicType) { bdlat_SymbolicConverter_Imp_resolveDynamicRhsProxy< LHS_TYPE, bdlat_TypeCategory::DynamicType> proxy = { this, lhs }; return bdlat_TypeCategoryUtil::accessByCategory(rhs, proxy); } template <class LHS_TYPE, class RHS_TYPE, class RHS_CATEGORY> inline int bdlat_SymbolicConverter_Imp::resolveDynamicTypes( LHS_TYPE *lhs, bdlat_TypeCategory::DynamicType, const RHS_TYPE& rhs, RHS_CATEGORY) { bdlat_SymbolicConverter_Imp_resolveDynamicLhsProxy< RHS_TYPE, RHS_CATEGORY> proxy = { this, &rhs }; return bdlat_TypeCategoryUtil::manipulateByCategory(lhs, proxy); } template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::resolveDynamicTypes( LHS_TYPE *lhs, LHS_CATEGORY, const RHS_TYPE& rhs, bdlat_TypeCategory::DynamicType) { bdlat_SymbolicConverter_Imp_resolveDynamicRhsProxy< LHS_TYPE, LHS_CATEGORY> proxy = { this, lhs }; return bdlat_TypeCategoryUtil::accessByCategory(rhs, proxy); } template <class LHS_TYPE, class LHS_CATEGORY, class RHS_TYPE, class RHS_CATEGORY> inline int bdlat_SymbolicConverter_Imp::resolveDynamicTypes( LHS_TYPE *lhs, LHS_CATEGORY lhsCategory, const RHS_TYPE& rhs, RHS_CATEGORY rhsCategory) { return convert(lhs, lhsCategory, rhs, rhsCategory); } // CREATORS inline bdlat_SymbolicConverter_Imp::bdlat_SymbolicConverter_Imp( bsl::ostream *errorStream) : d_errorStream_p(errorStream) { BSLS_ASSERT(d_errorStream_p); } // MANIPULATORS template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter_Imp::convert(LHS_TYPE *lhs, const RHS_TYPE& rhs) { typedef typename bdlat_TypeCategory::Select<LHS_TYPE>::Type LhsCategory; typedef typename bdlat_TypeCategory::Select<RHS_TYPE>::Type RhsCategory; return resolveDynamicTypes(lhs, LhsCategory(), rhs, RhsCategory()); } inline bsl::ostream& bdlat_SymbolicConverter_Imp::errorStream() { return *d_errorStream_p; } // ----------------------------------------------------- // class bdlat_SymbolicConverter_StoreValue<LVALUE_TYPE> // ----------------------------------------------------- // CREATORS template <class LVALUE_TYPE> inline bdlat_SymbolicConverter_StoreValue<LVALUE_TYPE>:: bdlat_SymbolicConverter_StoreValue(LVALUE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp) : d_destination_p(destination) , d_imp_p(imp) { } // ACCESSORS template <class LVALUE_TYPE> template <class RVALUE_TYPE, class INFO_TYPE> inline int bdlat_SymbolicConverter_StoreValue<LVALUE_TYPE>::operator()( const RVALUE_TYPE& object, const INFO_TYPE&) const { return d_imp_p->convert(d_destination_p, object); } template <class LVALUE_TYPE> template <class RVALUE_TYPE> inline int bdlat_SymbolicConverter_StoreValue<LVALUE_TYPE>::operator()( const RVALUE_TYPE& object) const { return d_imp_p->convert(d_destination_p, object); } // ---------------------------------------------------- // class bdlat_SymbolicConverter_LoadValue<RVALUE_TYPE> // ---------------------------------------------------- // CREATORS template <class RVALUE_TYPE> inline bdlat_SymbolicConverter_LoadValue<RVALUE_TYPE>:: bdlat_SymbolicConverter_LoadValue( const RVALUE_TYPE& value, bdlat_SymbolicConverter_Imp *imp) : d_imp_p(imp) , d_value(value) { } // ACCESSORS template <class RVALUE_TYPE> template <class LVALUE_TYPE, class INFO_TYPE> inline int bdlat_SymbolicConverter_LoadValue<RVALUE_TYPE>::operator()( LVALUE_TYPE *object, const INFO_TYPE&) const { return d_imp_p->convert(object, d_value); } template <class RVALUE_TYPE> template <class LVALUE_TYPE> inline int bdlat_SymbolicConverter_LoadValue<RVALUE_TYPE>::operator()( LVALUE_TYPE *object) const { return d_imp_p->convert(object, d_value); } // ------------------------------------------------------------ // class bdlat_SymbolicConverter_StoreInSequence<SEQUENCE_TYPE> // ------------------------------------------------------------ // CREATORS template <class SEQUENCE_TYPE> inline bdlat_SymbolicConverter_StoreInSequence<SEQUENCE_TYPE>:: bdlat_SymbolicConverter_StoreInSequence( SEQUENCE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp) : d_destination_p(destination) , d_imp_p(imp) { } // ACCESSORS template <class SEQUENCE_TYPE> template <class SOURCE_MEMBER_TYPE, class INFO_TYPE> inline int bdlat_SymbolicConverter_StoreInSequence<SEQUENCE_TYPE>::operator()( const SOURCE_MEMBER_TYPE& sourceMember, const INFO_TYPE& info) const { enum { k_SUCCESS = 0, k_FAILURE = -7 }; bdlat_SymbolicConverter_LoadValue<SOURCE_MEMBER_TYPE> loadSourceValue( sourceMember, d_imp_p); if (0 != bdlat_SequenceFunctions::manipulateAttribute(d_destination_p, loadSourceValue, info.name(), info.nameLength())) { d_imp_p->errorStream() << "Failed to convert attribute '" << bslstl::StringRef(info.name(), info.nameLength()) << "'\n"; return k_FAILURE; // RETURN } return k_SUCCESS; } // -------------------------------------------------------- // class bdlat_SymbolicConverter_StoreInChoice<CHOICE_TYPE> // -------------------------------------------------------- // CREATORS template <class CHOICE_TYPE> inline bdlat_SymbolicConverter_StoreInChoice<CHOICE_TYPE>:: bdlat_SymbolicConverter_StoreInChoice(CHOICE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp) : d_destination_p(destination) , d_imp_p(imp) { } // ACCESSORS template <class CHOICE_TYPE> template <class SOURCE_MEMBER_TYPE, class INFO_TYPE> int bdlat_SymbolicConverter_StoreInChoice<CHOICE_TYPE>::operator()( const SOURCE_MEMBER_TYPE& sourceMember, const INFO_TYPE& info) const { enum { k_SUCCESS = 0, k_FAILURE = -8 }; // Make the selection. if (0 != bdlat_ChoiceFunctions::makeSelection(d_destination_p, info.name(), info.nameLength())) { d_imp_p->errorStream() << "Failed to make selection '" << bslstl::StringRef(info.name(), info.nameLength()) << "'\n"; return k_FAILURE; // RETURN } // Assign the value. bdlat_SymbolicConverter_LoadValue<SOURCE_MEMBER_TYPE> loadSourceValue( sourceMember, d_imp_p); if (0 != bdlat_ChoiceFunctions::manipulateSelection(d_destination_p, loadSourceValue)) { d_imp_p->errorStream() << "Failed to convert selection '" << bslstl::StringRef(info.name(), info.nameLength()) << "'\n"; return k_FAILURE; // RETURN } return k_SUCCESS; } // ------------------------------------------------------------- // class bdlat_SymbolicConverter_StoreInArrayElement<ARRAY_TYPE> // ------------------------------------------------------------- // CREATORS template <class ARRAY_TYPE> inline bdlat_SymbolicConverter_StoreInArrayElement<ARRAY_TYPE>:: bdlat_SymbolicConverter_StoreInArrayElement(ARRAY_TYPE *array, int index, bdlat_SymbolicConverter_Imp *imp) : d_array_p(array) , d_imp_p(imp) , d_index(index) { } // ACCESSORS template <class ARRAY_TYPE> template <class SOURCE_ELEMENT_TYPE> inline int bdlat_SymbolicConverter_StoreInArrayElement<ARRAY_TYPE>::operator()( const SOURCE_ELEMENT_TYPE& sourceElement) const { bdlat_SymbolicConverter_LoadValue<SOURCE_ELEMENT_TYPE> loadSourceValue( sourceElement, d_imp_p); return bdlat_ArrayFunctions::manipulateElement(d_array_p, loadSourceValue, d_index); } // ------------------------------------------------------------ // class bdlat_SymbolicConverter_StoreInNullable<NULLABLE_TYPE> // ------------------------------------------------------------ // CREATORS template <class NULLABLE_TYPE> inline bdlat_SymbolicConverter_StoreInNullable<NULLABLE_TYPE>:: bdlat_SymbolicConverter_StoreInNullable( NULLABLE_TYPE *destination, bdlat_SymbolicConverter_Imp *imp) : d_destination_p(destination) , d_imp_p(imp) { } // ACCESSORS template <class NULLABLE_TYPE> template <class VALUE_TYPE> inline int bdlat_SymbolicConverter_StoreInNullable<NULLABLE_TYPE>::operator()( const VALUE_TYPE& value) const { bdlat_NullableValueFunctions::makeValue(d_destination_p); // Assign the value. bdlat_SymbolicConverter_LoadValue<VALUE_TYPE> loadSourceValue(value, d_imp_p); return bdlat_NullableValueFunctions::manipulateValue(d_destination_p, loadSourceValue); } // ------------------------------ // struct bdlat_SymbolicConverter // ------------------------------ template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter::convert(LHS_TYPE *lhs, const RHS_TYPE& rhs) { bsl::ostream nullStream(0); return bdlat_SymbolicConverter::convert(lhs, rhs, nullStream); } template <class LHS_TYPE, class RHS_TYPE> inline int bdlat_SymbolicConverter::convert(LHS_TYPE *lhs, const RHS_TYPE& rhs, bsl::ostream& errorStream) { bdlat_ValueTypeFunctions::reset(lhs); bdlat_SymbolicConverter_Imp imp(&errorStream); return imp.convert(lhs, rhs); } } // 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 ----------------------------------