Logo ROOT   6.16/01
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.
31using 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.
39int MPSend(TSocket *s, unsigned code);
40
41template<class T, typename std::enable_if<std::is_class<T>::value>::type * = nullptr>
42int MPSend(TSocket *s, unsigned code, T obj);
43
44template < class T, typename std::enable_if < !std::is_class<T>::value &&!std::is_pointer<T>::value >::type * = nullptr >
45int MPSend(TSocket *s, unsigned code, T obj);
46
47template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type * = nullptr>
48int MPSend(TSocket *s, unsigned code, T obj);
49
50template < class T, typename std::enable_if < std::is_pointer<T>::value &&std::is_constructible<TObject *, T>::value >::type * = nullptr >
51int MPSend(TSocket *s, unsigned code, T obj);
52
54
55
56//this version reads classes from the message
57template<class T, typename std::enable_if<std::is_class<T>::value>::type * = nullptr>
59
60//this version reads built-in types from the message
61template < 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
65template<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
69template < 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
90template<class T, typename std::enable_if<std::is_class<T>::value>::type *>
91int 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)
110template < class T, typename std::enable_if < !std::is_class<T>::value &&!std::is_pointer<T>::value >::type * >
111int 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?
121template<class T, typename std::enable_if<std::is_same<const char *, T>::value>::type *>
122int 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
132template < class T, typename std::enable_if < std::is_pointer<T>::value && std::is_constructible<TObject *, T>::value >::type * >
133int 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).
156template<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
167template < 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
176template<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
185template < 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
void Class()
Definition: Class.C:29
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
MPCodeBufPair MPRecv(TSocket *s)
Receive message from a socket.
Definition: MPSendRecv.cxx:54
int MPSend(TSocket *s, unsigned code)
Send a message with the specified code on the specified socket.
Definition: MPSendRecv.cxx:32
T ReadBuffer(TBufferFile *buf)
One of the template functions used to read objects from messages.
Definition: MPSendRecv.h:157
#define c(i)
Definition: RSha256.hxx:101
unsigned long ULong_t
Definition: RtypesCore.h:51
void Error(const char *location, const char *msgfmt,...)
int type
Definition: TGX11.cxx:120
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition: TBufferFile.h:46
virtual void WriteULong(ULong_t l)
Definition: TBufferFile.h:327
virtual void WriteBuf(const void *buf, Int_t max)
Write max bytes from buf into the I/O buffer.
virtual void WriteUInt(UInt_t i)
Definition: TBufferFile.h:313
virtual char * ReadString(char *s, Int_t max)
Read string from I/O buffer.
virtual void * ReadObjectAny(const TClass *cast)
Read object from I/O buffer.
virtual Int_t WriteObjectAny(const void *obj, const TClass *ptrClass, Bool_t cacheReuse=kTRUE)
Write object to I/O buffer.
Definition: TBufferIO.cxx:492
Int_t BufferSize() const
Definition: TBuffer.h:94
@ kWrite
Definition: TBuffer.h:70
Int_t Length() const
Definition: TBuffer.h:96
char * Buffer() const
Definition: TBuffer.h:93
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
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
double T(double x)
Definition: ChebyshevPol.h:34
static constexpr double s