Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:11:16

0001 /* @(#)root/multiproc:$Id$ */
0002 // Author: Enrico Guiraud July 2015
0003 
0004 /*************************************************************************
0005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
0006  * All rights reserved.                                                  *
0007  *                                                                       *
0008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
0009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
0010  *************************************************************************/
0011 
0012 #ifndef ROOT_MPSendRecv
0013 #define ROOT_MPSendRecv
0014 
0015 #include "TBufferFile.h"
0016 #include "TClass.h"
0017 #include "TError.h"
0018 #include "TSocket.h"
0019 #include <memory> //unique_ptr
0020 #include <type_traits> //enable_if
0021 #include <typeinfo> //typeid
0022 #include <utility> //pair
0023 #include <string>
0024 
0025 //////////////////////////////////////////////////////////////////////////
0026 /// An std::pair that wraps the code and optional object contained in a message.
0027 /// \param first message code
0028 /// \param second a smart pointer to a TBufferFile that contains the message object\n
0029 /// The smart pointer is null if the message does not contain an object
0030 /// but only consists of a code. See MPRecv() description on how to
0031 /// retrieve the object from the TBufferFile.
0032 using MPCodeBufPair = std::pair<unsigned, std::unique_ptr<TBufferFile>>;
0033 
0034 
0035 /************ FUNCTIONS' DECLARATIONS *************/
0036 
0037 // There are several versions of this function: this is one sends a
0038 // message with a code and no object. The templated versions are used
0039 // to send a code and an object of any non-pointer type.
0040 int MPSend(TSocket *s, unsigned code);
0041 
0042 template<class T, typename std::enable_if<std::is_class<T>::value>::type * = nullptr>
0043 int MPSend(TSocket *s, unsigned code, T obj);
0044 
0045 template < class T, typename std::enable_if < !std::is_class<T>::value  &&!std::is_pointer<T>::value >::type * = nullptr >
0046 int MPSend(TSocket *s, unsigned code, T obj);
0047 
0048 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type * = nullptr>
0049 int MPSend(TSocket *s, unsigned code, T obj);
0050 
0051 template < class T, typename std::enable_if < std::is_pointer<T>::value  &&std::is_constructible<TObject *, T>::value >::type * = nullptr >
0052 int MPSend(TSocket *s, unsigned code, T obj);
0053 
0054 MPCodeBufPair MPRecv(TSocket *s);
0055 
0056 
0057 //this version reads classes from the message
0058 template<class T, typename std::enable_if<std::is_class<T>::value>::type * = nullptr>
0059 T ReadBuffer(TBufferFile *buf);
0060 
0061 //this version reads built-in types from the message
0062 template < class T, typename std::enable_if < !std::is_class<T>::value  &&!std::is_pointer<T>::value >::type * = nullptr >
0063 T ReadBuffer(TBufferFile *buf);
0064 
0065 //this version reads std::string and c-strings from the message
0066 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type * = nullptr>
0067 T ReadBuffer(TBufferFile *buf);
0068 
0069 //this version reads a TObject* from the message
0070 template < class T, typename std::enable_if < std::is_pointer<T>::value  &&std::is_constructible<TObject *, T>::value >::type * = nullptr >
0071 T ReadBuffer(TBufferFile *buf);
0072 
0073 
0074 /************ TEMPLATE FUNCTIONS' IMPLEMENTATIONS *******************/
0075 
0076 //////////////////////////////////////////////////////////////////////////
0077 /// Send a message with a code and an object to socket s.
0078 /// The number of bytes sent is returned, as per TSocket::SendRaw.
0079 /// This standalone function can be used to send a code and possibly
0080 /// an object on a given socket. This function does not check whether the
0081 /// socket connection is in a valid state. MPRecv() must be used to
0082 /// retrieve the contents of the message.\n
0083 /// **Note:** only objects the headers of which have been parsed by
0084 /// cling can be sent using MPSend(). User-defined types can be made available to
0085 /// cling via a call like `gSystem->ProcessLine("#include \"header.h\"")`.
0086 /// Pointer types cannot be sent via MPSend() (with the exception of const char*).
0087 /// \param s a pointer to a valid TSocket. No validity checks are performed\n
0088 /// \param code the code to be sent
0089 /// \param obj the object to be sent
0090 /// \return the number of bytes sent, as per TSocket::SendRaw
0091 template<class T, typename std::enable_if<std::is_class<T>::value>::type *>
0092 int MPSend(TSocket *s, unsigned code, T obj)
0093 {
0094    TClass *c = TClass::GetClass<T>();
0095    if (!c) {
0096       Error("MPSend", "[E] Could not find cling definition for class %s\n", typeid(T).name());
0097       return -1;
0098    }
0099    TBufferFile objBuf(TBuffer::kWrite);
0100    objBuf.WriteObjectAny(&obj, c);
0101    TBufferFile wBuf(TBuffer::kWrite);
0102    wBuf.WriteUInt(code);
0103    wBuf.WriteULong(objBuf.Length());
0104    wBuf.WriteBuf(objBuf.Buffer(), objBuf.Length());
0105    return s->SendRaw(wBuf.Buffer(), wBuf.Length());
0106 }
0107 
0108 /// \cond
0109 // send a built-in type that is not a pointer (under the hypothesis that
0110 // TBuffer's operator<< works with any built-in type that is not a pointer)
0111 template < class T, typename std::enable_if < !std::is_class<T>::value  &&!std::is_pointer<T>::value >::type * >
0112 int MPSend(TSocket *s, unsigned code, T obj)
0113 {
0114    TBufferFile wBuf(TBuffer::kWrite);
0115    ULong_t size = sizeof(T);
0116    wBuf << code << size << obj;
0117    return s->SendRaw(wBuf.Buffer(), wBuf.Length());
0118 }
0119 
0120 // send an null-terminated c-string or an std::string (which is converted to a c-string)
0121 //TODO can this become a partial specialization instead?
0122 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type *>
0123 int MPSend(TSocket *s, unsigned code, T obj)
0124 {
0125    TBufferFile wBuf(TBuffer::kWrite);
0126    wBuf.WriteUInt(code);
0127    wBuf.WriteULong(strlen(obj) + 1); //strlen does not count the trailing \0
0128    wBuf.WriteString(obj);
0129    return s->SendRaw(wBuf.Buffer(), wBuf.Length());
0130 }
0131 
0132 // send a TObject*. Allows polymorphic behaviour and pters to derived classes
0133 template < class T, typename std::enable_if < std::is_pointer<T>::value && std::is_constructible<TObject *, T>::value >::type * >
0134 int MPSend(TSocket *s, unsigned code, T obj)
0135 {
0136    //find out the size of the object
0137    TBufferFile objBuf(TBuffer::kWrite);
0138    if(obj != nullptr)
0139       objBuf.WriteObjectAny(obj, obj->IsA());
0140 
0141    //write everything together in a buffer
0142    TBufferFile wBuf(TBuffer::kWrite);
0143    wBuf.WriteUInt(code);
0144    wBuf.WriteULong(objBuf.Length());
0145    if(objBuf.Length())
0146       wBuf.WriteBuf(objBuf.Buffer(), objBuf.Length());
0147    return s->SendRaw(wBuf.Buffer(), wBuf.Length());
0148 }
0149 
0150 /// \endcond
0151 
0152 //////////////////////////////////////////////////////////////////////////
0153 /// One of the template functions used to read objects from messages.
0154 /// Different implementations are provided for different types of objects:
0155 /// classes, non-pointer built-ins and const char*. Reading pointers is
0156 /// not implemented (at the time of writing, sending pointers is not either).
0157 template<class T, typename std::enable_if<std::is_class<T>::value>::type *>
0158 T ReadBuffer(TBufferFile *buf)
0159 {
0160    TClass *c = TClass::GetClass(typeid(T));
0161    T *objp = (T *)buf->ReadObjectAny(c);
0162    T obj = *objp; //this is slow, but couldn't find a better way of returning a T without leaking memory
0163    delete objp;
0164    return obj;
0165 }
0166 
0167 /// \cond
0168 template < class T, typename std::enable_if < !std::is_class<T>::value  &&!std::is_pointer<T>::value >::type * >
0169 T ReadBuffer(TBufferFile *buf)
0170 {
0171    //read built-in type
0172    T obj;
0173    *(buf) >> obj;
0174    return obj;
0175 }
0176 
0177 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type *>
0178 T ReadBuffer(TBufferFile *buf)
0179 {
0180    //read c-string
0181    char *c = new char[buf->BufferSize()];
0182    buf->ReadString(c, buf->BufferSize());
0183    return c;
0184 }
0185 
0186 template < class T, typename std::enable_if < std::is_pointer<T>::value  &&std::is_constructible<TObject *, T>::value >::type * >
0187 T ReadBuffer(TBufferFile *buf)
0188 {
0189    //read TObject*
0190    using objType = typename std::remove_pointer<T>::type;
0191    return (T)buf->ReadObjectAny(objType::Class());
0192 }
0193 /// \endcond
0194 
0195 #endif