Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
explicitely capture variables in lambda to please sonar
[simgrid.git] / src / mc / RemotePtr.hpp
1 /* Copyright (c) 2008-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef SIMGRID_MC_REMOTE_PTR_HPP
8 #define SIMGRID_MC_REMOTE_PTR_HPP
9
10 #include <cstddef>
11 #include <cstdint>
12 #include <cstring>
13
14 #include <stdexcept>
15 #include <type_traits>
16
17 namespace simgrid {
18 namespace mc {
19
20 /** HACK, A value from another process
21  *
22  *  This represents a value from another process:
23  *
24  *  * constructor/destructor are disabled;
25  *
26  *  * raw memory copy (std::memcpy) is used to copy Remote<T>;
27  *
28  *  * raw memory comparison is used to compare them;
29  *
30  *  * when T is a trivial type, Remote is convertible to a T.
31  *
32  *  We currently only handle the case where the type has the same layout
33  *  in the current process and in the target process: we don't handle
34  *  cross-architecture (such as 32-bit/64-bit access).
35  */
36 template<class T>
37 union Remote {
38 private:
39   T buffer;
40 public:
41   Remote() {}
42   ~Remote() {}
43   Remote(T& p)
44   {
45     std::memcpy(&buffer, &p, sizeof(buffer));
46   }
47   Remote(Remote const& that)
48   {
49     std::memcpy(&buffer, &that.buffer, sizeof(buffer));
50   }
51   Remote& operator=(Remote const& that)
52   {
53     std::memcpy(&buffer, &that.buffer, sizeof(buffer));
54     return *this;
55   }
56   T*       getBuffer() { return &buffer; }
57   const T* getBuffer() const { return &buffer; }
58   std::size_t getBufferSize() const { return sizeof(T); }
59   operator T() const {
60     static_assert(std::is_trivial<T>::value, "Cannot convert non trivial type");
61     return buffer;
62   }
63   void clear()
64   {
65     std::memset(static_cast<void*>(&buffer), 0, sizeof(T));
66   }
67
68 };
69
70 /** Pointer to a remote address-space (process, snapshot)
71  *
72  *  With this we can clearly identify the expected type of an address in the
73  *  remote process while avoiding to use native local pointers.
74  *
75  *  Some operators (+/-) assume use the size of the underlying element. This
76  *  only works if the target applications is using the same target: it won't
77  *  work for example, when inspecting a 32 bit application from a 64 bit
78  *  model-checker.
79  *
80  *  We do not actually store the target address space because we can
81  *  always detect it in context. This way `RemotePtr` is as efficient
82  *  as a `uint64_t`.
83  */
84 template<class T> class RemotePtr {
85   std::uint64_t address_;
86 public:
87   RemotePtr() : address_(0) {}
88   RemotePtr(std::uint64_t address) : address_(address) {}
89   RemotePtr(T* address) : address_((std::uintptr_t)address) {}
90   RemotePtr(Remote<T*> p) : RemotePtr(*p.getBuffer()) {}
91   std::uint64_t address() const { return address_; }
92
93   /** Turn into a local pointer
94    *
95    (if the remote process is not, in fact, remote) */
96   T* local() const { return (T*) address_; }
97
98   operator bool() const
99   {
100     return address_;
101   }
102   bool operator!() const
103   {
104     return !address_;
105   }
106   operator RemotePtr<void>() const
107   {
108     return RemotePtr<void>(address_);
109   }
110   RemotePtr<T> operator+(std::uint64_t n) const
111   {
112     return RemotePtr<T>(address_ + n * sizeof(T));
113   }
114   RemotePtr<T> operator-(std::uint64_t n) const
115   {
116     return RemotePtr<T>(address_ - n * sizeof(T));
117   }
118   RemotePtr<T>& operator+=(std::uint64_t n)
119   {
120     address_ += n * sizeof(T);
121     return *this;
122   }
123   RemotePtr<T>& operator-=(std::uint64_t n)
124   {
125     address_ -= n * sizeof(T);
126     return *this;
127   }
128 };
129
130 template<class X, class Y>
131 bool operator<(RemotePtr<X> const& x, RemotePtr<Y> const& y)
132 {
133   return x.address() < y.address();
134 }
135
136 template<class X, class Y>
137 bool operator>(RemotePtr<X> const& x, RemotePtr<Y> const& y)
138 {
139   return x.address() > y.address();
140 }
141
142 template<class X, class Y>
143 bool operator>=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
144 {
145   return x.address() >= y.address();
146 }
147
148 template<class X, class Y>
149 bool operator<=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
150 {
151   return x.address() <= y.address();
152 }
153
154 template<class X, class Y>
155 bool operator==(RemotePtr<X> const& x, RemotePtr<Y> const& y)
156 {
157   return x.address() == y.address();
158 }
159
160 template<class X, class Y>
161 bool operator!=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
162 {
163   return x.address() != y.address();
164 }
165
166 template<class T> inline
167 RemotePtr<T> remote(T *p)
168 {
169   return RemotePtr<T>(p);
170 }
171
172 template<class T=void> inline
173 RemotePtr<T> remote(uint64_t p)
174 {
175   return RemotePtr<T>(p);
176 }
177
178 }
179 }
180
181 #endif