Logo ROOT   6.10/09
Reference Guide
MPSendRecv.h
Go to the documentation of this file.
1 /* @(#)root/multiproc:$Id$ */
2 // Author: Enrico Guiraud July 2015
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #ifndef ROOT_MPSendRecv
13 #define ROOT_MPSendRecv
14 
15 #include "TBufferFile.h"
16 #include "TClass.h"
17 #include "TError.h"
18 #include "TSocket.h"
19 #include <memory> //unique_ptr
20 #include <type_traits> //enable_if
21 #include <typeinfo> //typeid
22 #include <utility> //pair
23 
24 //////////////////////////////////////////////////////////////////////////
25 /// An std::pair that wraps the code and optional object contained in a message.
26 /// \param first message code
27 /// \param second a smart pointer to a TBufferFile that contains the message object\n
28 /// The smart pointer is null if the message does not contain an object
29 /// but only consists of a code. See MPRecv() description on how to
30 /// retrieve the object from the TBufferFile.
31 using MPCodeBufPair = std::pair<unsigned, std::unique_ptr<TBufferFile>>;
32 
33 
34 /************ FUNCTIONS' DECLARATIONS *************/
35 
36 // There are several versions of this function: this is one sends a
37 // message with a code and no object. The templated versions are used
38 // to send a code and an object of any non-pointer type.
39 int MPSend(TSocket *s, unsigned code);
40 
41 template<class T, typename std::enable_if<std::is_class<T>::value>::type * = nullptr>
42 int MPSend(TSocket *s, unsigned code, T obj);
43 
44 template < class T, typename std::enable_if < !std::is_class<T>::value &&!std::is_pointer<T>::value >::type * = nullptr >
45 int MPSend(TSocket *s, unsigned code, T obj);
46 
47 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type * = nullptr>
48 int MPSend(TSocket *s, unsigned code, T obj);
49 
50 template < class T, typename std::enable_if < std::is_pointer<T>::value &&std::is_constructible<TObject *, T>::value >::type * = nullptr >
51 int MPSend(TSocket *s, unsigned code, T obj);
52 
54 
55 
56 //this version reads classes from the message
57 template<class T, typename std::enable_if<std::is_class<T>::value>::type * = nullptr>
59 
60 //this version reads built-in types from the message
61 template < class T, typename std::enable_if < !std::is_class<T>::value &&!std::is_pointer<T>::value >::type * = nullptr >
63 
64 //this version reads std::string and c-strings from the message
65 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type * = nullptr>
67 
68 //this version reads a TObject* from the message
69 template < class T, typename std::enable_if < std::is_pointer<T>::value &&std::is_constructible<TObject *, T>::value >::type * = nullptr >
71 
72 
73 /************ TEMPLATE FUNCTIONS' IMPLEMENTATIONS *******************/
74 
75 //////////////////////////////////////////////////////////////////////////
76 /// Send a message with a code and an object to socket s.
77 /// The number of bytes sent is returned, as per TSocket::SendRaw.
78 /// This standalone function can be used to send a code and possibly
79 /// an object on a given socket. This function does not check whether the
80 /// socket connection is in a valid state. MPRecv() must be used to
81 /// retrieve the contents of the message.\n
82 /// **Note:** only objects the headers of which have been parsed by
83 /// cling can be sent using MPSend(). User-defined types can be made available to
84 /// cling via a call like `gSystem->ProcessLine("#include \"header.h\"")`.
85 /// Pointer types cannot be sent via MPSend() (with the exception of const char*).
86 /// \param s a pointer to a valid TSocket. No validity checks are performed\n
87 /// \param code the code to be sent
88 /// \param obj the object to be sent
89 /// \return the number of bytes sent, as per TSocket::SendRaw
90 template<class T, typename std::enable_if<std::is_class<T>::value>::type *>
91 int MPSend(TSocket *s, unsigned code, T obj)
92 {
93  TClass *c = TClass::GetClass(typeid(T));
94  if (!c) {
95  Error("MPSend", "[E] Could not find cling definition for class %s\n", typeid(T).name());
96  return -1;
97  }
99  objBuf.WriteObjectAny(&obj, c);
101  wBuf.WriteUInt(code);
102  wBuf.WriteULong(objBuf.Length());
103  wBuf.WriteBuf(objBuf.Buffer(), objBuf.Length());
104  return s->SendRaw(wBuf.Buffer(), wBuf.Length());
105 }
106 
107 /// \cond
108 // send a built-in type that is not a pointer (under the hypothesis that
109 // TBuffer's operator<< works with any built-in type that is not a pointer)
110 template < class T, typename std::enable_if < !std::is_class<T>::value &&!std::is_pointer<T>::value >::type * >
111 int MPSend(TSocket *s, unsigned code, T obj)
112 {
114  ULong_t size = sizeof(T);
115  wBuf << code << size << obj;
116  return s->SendRaw(wBuf.Buffer(), wBuf.Length());
117 }
118 
119 // send an null-terminated c-string or an std::string (which is converted to a c-string)
120 //TODO can this become a partial specialization instead?
121 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type *>
122 int MPSend(TSocket *s, unsigned code, T obj)
123 {
125  wBuf.WriteUInt(code);
126  wBuf.WriteULong(strlen(obj) + 1); //strlen does not count the trailing \0
127  wBuf.WriteString(obj);
128  return s->SendRaw(wBuf.Buffer(), wBuf.Length());
129 }
130 
131 // send a TObject*. Allows polymorphic behaviour and pters to derived classes
132 template < class T, typename std::enable_if < std::is_pointer<T>::value && std::is_constructible<TObject *, T>::value >::type * >
133 int MPSend(TSocket *s, unsigned code, T obj)
134 {
135  //find out the size of the object
137  if(obj != nullptr)
138  objBuf.WriteObjectAny(obj, obj->IsA());
139 
140  //write everything together in a buffer
142  wBuf.WriteUInt(code);
143  wBuf.WriteULong(objBuf.Length());
144  if(objBuf.Length())
145  wBuf.WriteBuf(objBuf.Buffer(), objBuf.Length());
146  return s->SendRaw(wBuf.Buffer(), wBuf.Length());
147 }
148 
149 /// \endcond
150 
151 //////////////////////////////////////////////////////////////////////////
152 /// One of the template functions used to read objects from messages.
153 /// Different implementations are provided for different types of objects:
154 /// classes, non-pointer built-ins and const char*. Reading pointers is
155 /// not implemented (at the time of writing, sending pointers is not either).
156 template<class T, typename std::enable_if<std::is_class<T>::value>::type *>
158 {
159  TClass *c = TClass::GetClass(typeid(T));
160  T *objp = (T *)buf->ReadObjectAny(c);
161  T obj = *objp; //this is slow, but couldn't find a better way of returning a T without leaking memory
162  delete objp;
163  return obj;
164 }
165 
166 /// \cond
167 template < class T, typename std::enable_if < !std::is_class<T>::value &&!std::is_pointer<T>::value >::type * >
169 {
170  //read built-in type
171  T obj;
172  *(buf) >> obj;
173  return obj;
174 }
175 
176 template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type *>
178 {
179  //read c-string
180  char *c = new char[buf->BufferSize()];
181  buf->ReadString(c, buf->BufferSize());
182  return c;
183 }
184 
185 template < class T, typename std::enable_if < std::is_pointer<T>::value &&std::is_constructible<TObject *, T>::value >::type * >
187 {
188  //read TObject*
189  using objType = typename std::remove_pointer<T>::type;
190  return (T)buf->ReadObjectAny(objType::Class());
191 }
192 /// \endcond
193 
194 #endif
virtual void WriteString(const char *s)
Write string to I/O buffer.
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket...
Definition: TBufferFile.h:47
double T(double x)
Definition: ChebyshevPol.h:34
T ReadBuffer(TBufferFile *buf)
One of the template functions used to read objects from messages.
Definition: MPSendRecv.h:157
int MPSend(TSocket *s, unsigned code)
Send a message with the specified code on the specified socket.
Definition: MPSendRecv.cxx:32
virtual void * ReadObjectAny(const TClass *cast)
Read object from I/O buffer.
virtual void WriteULong(ULong_t l)
Definition: TBufferFile.h:385
Int_t Length() const
Definition: TBuffer.h:94
virtual Int_t SendRaw(const void *buffer, Int_t length, ESendRecvOptions opt=kDefault)
Send a raw buffer of specified length.
Definition: TSocket.cxx:620
void Class()
Definition: Class.C:29
virtual char * ReadString(char *s, Int_t max)
Read string from I/O buffer.
char * Buffer() const
Definition: TBuffer.h:91
void Error(const char *location, const char *msgfmt,...)
virtual void WriteUInt(UInt_t i)
Definition: TBufferFile.h:371
std::pair< unsigned, std::unique_ptr< TBufferFile > > MPCodeBufPair
An std::pair that wraps the code and optional object contained in a message.
Definition: MPSendRecv.h:31
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:71
virtual void WriteBuf(const void *buf, Int_t max)
Write max bytes from buf into the I/O buffer.
int type
Definition: TGX11.cxx:120
unsigned long ULong_t
Definition: RtypesCore.h:51
Int_t BufferSize() const
Definition: TBuffer.h:92
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2885
virtual Int_t WriteObjectAny(const void *obj, const TClass *ptrClass)
Write object to I/O buffer.
MPCodeBufPair MPRecv(TSocket *s)
Receive message from a socket.
Definition: MPSendRecv.cxx:54