/* Copyright 2012. Bloomberg Finance L.P. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: The above * copyright notice and this permission notice shall be included in all copies * or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ // blpapi_correlationid.h -*-C++-*- #ifndef INCLUDED_BLPAPI_CORRELATIONID #define INCLUDED_BLPAPI_CORRELATIONID //@PURPOSE: Provide a key to identify individual subscriptions or requests // //@CLASSES: // blpapi::CorrelationId: a key to track requests and subscriptions // //@DESCRIPTION: This component provides an identifier that is attached on to // individual subscriptions and requests. CorrelationId are used to distinguish // between various subscriptions and are a way to find the response for an // asynchronous request. #ifndef INCLUDED_BLPAPI_TYPES #include <blpapi_types.h> #endif #ifndef INCLUDED_BLPAPI_DEFS #include <blpapi_defs.h> #endif #ifdef __cplusplus extern "C" { #endif struct blpapi_ManagedPtr_t_; typedef struct blpapi_ManagedPtr_t_ blpapi_ManagedPtr_t; typedef int (*blpapi_ManagedPtr_ManagerFunction_t)( blpapi_ManagedPtr_t *managedPtr, const blpapi_ManagedPtr_t *srcPtr, int operation); typedef union { int intValue; void *ptr; } blpapi_ManagedPtr_t_data_; struct blpapi_ManagedPtr_t_ { void *pointer; blpapi_ManagedPtr_t_data_ userData[4]; blpapi_ManagedPtr_ManagerFunction_t manager; }; typedef struct blpapi_CorrelationId_t_ { unsigned int size:8; // fill in the size of this struct unsigned int valueType:4; // type of value held by this correlation id unsigned int classId:16; // user defined classification id unsigned int reserved:4; // for internal use must be 0 union { blpapi_UInt64_t intValue; blpapi_ManagedPtr_t ptrValue; } value; } blpapi_CorrelationId_t; #ifdef __cplusplus } #ifndef INCLUDED_CSTRING #include <cstring> #define INCLUDED_CSTRING #endif #ifndef INCLUDED_OSTREAM #include <ostream> #define INCLUDED_OSTREAM #endif #ifndef INCLUDED_ALGORITHM #include <algorithm> // for swap #define INCLUDED_ALGORITHM #endif namespace BloombergLP { namespace blpapi { // =================== // class CorrelationId // =================== class CorrelationId { // A key used to identify individual subscriptions or requests. // // CorrelationId objects are passed to many of the Session object // methods which initiate an asynchronous operations and are // obtained from Message objects which are delivered as a result // of those asynchronous operations. // // When subscribing or requesting information an application has // the choice of providing a CorrelationId they construct // themselves or allowing the session to construct one for // them. If the application supplies a CorrelationId it must not // re-use the value contained in it in another CorrelationId // whilst the original request or subscription is still active. // // It is possible that an application supplied CorrelationId and a // CorrelationId constructed by the API could return the same // result for asInteger(). However, they will not compare equal // using the defined operator== for CorrelationId and there is a // consistent order defined using the defined operator< for // CorrelationId. // // A CorrelationId constructed by an application can contain either // // - a 64 bit integer, // // - a simple pointer or // // - a "smart" pointer object (for example, tr1::shared_ptr) // // For 64 bit integers and simple pointers the values are copied // when CorrelationIds are copied and compared when CorrelationIds // are compared. // // For "smart" pointers the API can accommodate smart pointer classes // that meet the following restrictions. // // - It is no more than sizeof(void*)*4 bytes in size. // // - It is thread safe. // // - It performs all its necessary management as a direct side // effect of their copy constructor and destructor. // // - Its contents are location independent (that is given two // instances of a smart pointer s1 and s2 one can call std::swap(s1, // s2) ). // // The API will embed a smart pointer in the CorrelationId without // allocating memory separately for it. The specified 'smartPtr' // will have its copy constructor invoked when the CorrelationId // is copied and its destructor invoked when the CorrelationId is // destroyed so its resource management will continue to work as // normal. // // CorrelationId's based on a simple pointer and CorrelationId's // based on a smart pointer have the same ValueType // (POINTER_VALUE) which allows them to be compared to each other. // // A CorrelationId based on a simple pointer and a CorrelationId // based on a smart pointer will compare equally with operator== // as long as the pointer is the same. // // Likewise, when comparing two CorrelationId's based on a smart // pointer only the pointer value itself is used for the // comparison, the contents of the smart pointer object are // ignored. blpapi_CorrelationId_t d_impl; void copy(const blpapi_CorrelationId_t& src); template <typename TYPE> static int managerFunc(blpapi_ManagedPtr_t *managedPtr, const blpapi_ManagedPtr_t *srcPtr, int operation); template <typename TYPE> static void assertSmartPtrFits(); public: // Possible return values for valueType() method. enum ValueType { UNSET_VALUE = BLPAPI_CORRELATION_TYPE_UNSET, // The CorrelationId is unset. That is, it was created by the default // CorrelationId constructor. INT_VALUE = BLPAPI_CORRELATION_TYPE_INT, // The CorrelationId was created from an integer supplied by the // user. POINTER_VALUE = BLPAPI_CORRELATION_TYPE_POINTER, // The CorrelationId was created from a pointer supplied by the user. AUTOGEN_VALUE = BLPAPI_CORRELATION_TYPE_AUTOGEN // The CorrelationId was created internally by API. }; // The maximum value allowed for classId enum { MAX_CLASS_ID = BLPAPI_CORRELATION_MAX_CLASS_ID // The maximum value // allowed for classId }; CorrelationId(); // The default constructor creates an uninitialized // CorrelationId. This will compare equal to another // CorrelationId object constructed using the default // constructor. The only valid operations on an uninitialized // CorrelationId are assignment, comparison for equality and // destruction. CorrelationId(const blpapi_CorrelationId_t &correlation); CorrelationId(const CorrelationId& original); // Copy constructor. If the specified 'original' contains a // smart pointer it will be copy constructed into this // CorrelationId. explicit CorrelationId(long long value, int classId = 0); // Construct a CorrelationId object and initialize it with the // specified integer 'value'. explicit CorrelationId(void *value, int classId = 0); // Construct a CorrelationId object and initialize it with the // specified pointer 'value'. template<typename TYPE> CorrelationId(const TYPE& smartPtr, void *pointerValue, int classId = 0); // Construct a CorrelationId object and initialize it with the // specified 'smartPtr' (whose copy constructor will be called // in the process) and with the specified 'pointerValue' which // should be the result of operator-> on the specified // 'smartPtr'. ~CorrelationId(); // Destroy this CorrelationId. If this CorrelationId contains // a smart pointer its destructor will be called. // MANIPULATORS blpapi_CorrelationId_t& impl(); void swap(CorrelationId &other); // Swap the value of this CorrelationId object and the // specified 'other' CorrelationId object. CorrelationId& operator=(const CorrelationId &rhs); // Assign to this CorrelationId object the value of the // specified 'rhs' CorrelationId object. Return a modifiable // reference to this object. // ACCESSORS ValueType valueType() const; // Return the type of this CorrelationId object. unsigned short classId() const; // Return the user defined classification of this correlation // correlation id object. void* asPointer() const; // Return the value of this CorrelationId as a pointer // value. The result is undefined if this CorrelationId does // not have valueType()==POINTER_VALUE. template<typename TYPE> TYPE asSmartPointer() const; // Return the CorrelationId as a smart pointer. long long asInteger() const; // Return the value of this CorrelationId as an integer // value. The result is undefined if this CorrelationId does // not have valueType()==INT_VALUE or // valueType()==AUTOGEN_VALUE. const blpapi_CorrelationId_t& impl() const; }; // FREE OPERATORS inline bool operator==(const CorrelationId& lhs, const CorrelationId& rhs); // Return true if the specified 'lhs' and 'rhs' CorrelationId // objects contain the same value. Return false otherwise. Two // CorrelationId objects contain the same value if the result of // valueType() is the same and the result of asPointer() or // asInteger() as appropriate is also the same. inline bool operator!=(const CorrelationId& lhs, const CorrelationId& rhs); // Equivalent to !(lhs==rhs). inline bool operator<(const CorrelationId& lhs, const CorrelationId& rhs); // Return true if the value of the specified 'lhs' CorrelationId // object is less than the value of the specified 'rhs' // CorrelationId object. Return false otherwise. The operator // takes account of the value of the CorrelationId as well as its // valueType() to ensure a consistent ordering amongst // CorrelationIds regardless of whether they are generated by the // API or the user. The operator is provided solely for // convenience for operations such as insertion into ordered // containers. //============================================================================= // INLINE FUNCTION DEFINITIONS //============================================================================= // ------------------- // class CorrelationId // ------------------- inline CorrelationId::CorrelationId() { std::memset(&d_impl, 0, sizeof(d_impl)); } inline CorrelationId::CorrelationId(const blpapi_CorrelationId_t &correlationId) { copy(correlationId); } inline CorrelationId::CorrelationId(const CorrelationId& original) { copy(original.d_impl); } inline CorrelationId::CorrelationId(long long intValue, int newClassId) { std::memset(&d_impl, 0, sizeof(d_impl)); d_impl.size = static_cast<unsigned>(sizeof(d_impl)); d_impl.valueType = INT_VALUE; d_impl.value.intValue = intValue; d_impl.classId = newClassId; } inline CorrelationId::CorrelationId(void *ptrValue, int newClassId) { std::memset(&d_impl, 0, sizeof(d_impl)); d_impl.size = static_cast<unsigned>(sizeof(d_impl)); d_impl.valueType = POINTER_VALUE; d_impl.value.ptrValue.pointer = ptrValue; d_impl.classId = newClassId; } template <typename TYPE> inline CorrelationId::CorrelationId(const TYPE& smartPtr, void *ptrValue, int newClassId) { // If you get a compiler error here, the specified smart pointer does not // fit in the CorrelationId and cannot be used at this time. assertSmartPtrFits<TYPE>(); std::memset(&d_impl, 0, sizeof(d_impl)); d_impl.size = sizeof(d_impl); d_impl.valueType = POINTER_VALUE; d_impl.classId = newClassId; d_impl.value.ptrValue.pointer = ptrValue; d_impl.value.ptrValue.manager = &CorrelationId::managerFunc<TYPE>; void *arena = (void *)d_impl.value.ptrValue.userData; new (arena) TYPE(smartPtr); } inline CorrelationId::~CorrelationId() { if (POINTER_VALUE == valueType()) { blpapi_ManagedPtr_ManagerFunction_t &manager = d_impl.value.ptrValue.manager; if (manager) { manager(&d_impl.value.ptrValue, 0, BLPAPI_MANAGEDPTR_DESTROY); } } } inline void CorrelationId::swap(CorrelationId &other) { std::swap(other.d_impl, d_impl); } inline CorrelationId& CorrelationId::operator=(const CorrelationId &rhs) { if (&rhs == this) { return *this; } CorrelationId tmp(rhs); tmp.swap(*this); return *this; } inline blpapi_CorrelationId_t& CorrelationId::impl() { return d_impl; } inline CorrelationId::ValueType CorrelationId::valueType() const { return (ValueType)d_impl.valueType; } inline unsigned short CorrelationId::classId() const { return d_impl.classId; } inline void* CorrelationId::asPointer() const { return d_impl.value.ptrValue.pointer; } template<typename TYPE> inline TYPE CorrelationId::asSmartPointer() const { return *(TYPE *)d_impl.value.ptrValue.userData; } inline long long CorrelationId::asInteger() const { return d_impl.value.intValue; } inline const blpapi_CorrelationId_t& CorrelationId::impl() const { return d_impl; } inline void CorrelationId::copy(const blpapi_CorrelationId_t& src) { d_impl = src; if (POINTER_VALUE == valueType()) { blpapi_ManagedPtr_ManagerFunction_t& manager = d_impl.value.ptrValue.manager; if (manager) { manager(&d_impl.value.ptrValue, &src.value.ptrValue, BLPAPI_MANAGEDPTR_COPY); } } } template <typename TYPE> inline int CorrelationId::managerFunc(blpapi_ManagedPtr_t *managedPtr, const blpapi_ManagedPtr_t *srcPtr, int operation) { if (operation == BLPAPI_MANAGEDPTR_COPY) { managedPtr->pointer = srcPtr->pointer; managedPtr->manager = srcPtr->manager; void *arena = managedPtr->userData; new (arena) TYPE(*((TYPE*)&srcPtr->userData[0])); } else if (operation == BLPAPI_MANAGEDPTR_DESTROY) { TYPE *managedPtr_p = (TYPE*)&managedPtr->userData[0]; managedPtr_p->~TYPE(); } return 0; } template <typename TYPE> inline void CorrelationId::assertSmartPtrFits() { if (false) { // If you get a compiler error here, the specified smart pointer does // not fit in the CorrelationId and cannot be used at this time. char errorIfSmartPtrDoesNotFit[ sizeof(TYPE) <= (sizeof(void*)*4) ? 1 : -1]; (void)errorIfSmartPtrDoesNotFit; } } inline bool operator==(const CorrelationId& lhs, const CorrelationId& rhs) { if (lhs.valueType() != rhs.valueType()) { return false; } if (lhs.classId() != rhs.classId()) { return false; } if (lhs.valueType() == CorrelationId::POINTER_VALUE) { if (lhs.asPointer() != rhs.asPointer()) { return false; } } else if (lhs.asInteger() != rhs.asInteger()) { return false; } return true; } inline bool operator!=(const CorrelationId& lhs, const CorrelationId& rhs) { return !(lhs == rhs); } inline bool operator<(const CorrelationId& lhs, const CorrelationId& rhs) { return std::memcmp(&lhs.impl(), &rhs.impl(), sizeof(rhs.impl())) < 0; } inline std::ostream& operator<<(std::ostream& os, const CorrelationId& correlator) { const char *valueType = 0; switch (correlator.valueType()) { case CorrelationId::UNSET_VALUE: valueType = "UNSET"; break; case CorrelationId::INT_VALUE: valueType = "INT"; break; case CorrelationId::POINTER_VALUE: valueType = "POINTER"; break; case CorrelationId::AUTOGEN_VALUE: valueType = "AUTOGEN"; break; default: valueType = "UNKNOWN"; } os << "[ valueType=" << valueType << " classId=" << correlator.classId() << " value="; if (correlator.valueType() == CorrelationId::POINTER_VALUE) { os << correlator.asPointer(); } else os << correlator.asInteger(); os << " ]"; return os; } } // close namespace blpapi } // close namespace BloombergLP #endif // #ifdef __cplusplus #endif // #ifndef INCLUDED_BLPAPI_CORRELATIONID