Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
5c11ddc1c5c4554f6d317985668e0ff344efca02
[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 template<class M, class T, class Enable = void>
21 struct pointer_to_data_member {};
22 template<class M, class T>
23 struct pointer_to_data_member<M,T,typename std::enable_if< std::is_union<M>::value || std::is_class<M>::value >::type> {
24   typedef T M::* type;
25 };
26
27 template<class M, class T>
28 using pointer_to_data_member_t = typename pointer_to_data_member<M,T>::type;
29
30 /** HACK, A value from another process
31  *
32  *  This represents a value from another process:
33  *
34  *  * constructor/destructor are disabled;
35  *
36  *  * raw memory copy (std::memcpy) is used to copy Remote<T>;
37  *
38  *  * raw memory comparison is used to compare them;
39  *
40  *  * when T is a trivial type, Remote is convertible to a T.
41  *
42  *  We currently only handle the case where the type has the same layout
43  *  in the current process and in the target process: we don't handle
44  *  cross-architecture (such as 32-bit/64-bit access).
45  */
46 template<class T>
47 union Remote {
48 private:
49   T buffer;
50 public:
51   Remote() {}
52   ~Remote() {}
53   Remote(T& p)
54   {
55     std::memcpy(&buffer, &p, sizeof(buffer));
56   }
57   Remote(Remote const& that)
58   {
59     std::memcpy(&buffer, &that.buffer, sizeof(buffer));
60   }
61   Remote& operator=(Remote const& that)
62   {
63     std::memcpy(&buffer, &that.buffer, sizeof(buffer));
64     return *this;
65   }
66   T*       getBuffer() { return &buffer; }
67   const T* getBuffer() const { return &buffer; }
68   std::size_t getBufferSize() const { return sizeof(T); }
69   operator T() const {
70     static_assert(std::is_trivial<T>::value, "Cannot convert non trivial type");
71     return buffer;
72   }
73   void clear()
74   {
75     std::memset(static_cast<void*>(&buffer), 0, sizeof(T));
76   }
77
78 };
79
80 /** Pointer to a remote address-space (process, snapshot)
81  *
82  *  With this we can clearly identify the expected type of an address in the
83  *  remote process while avoiding to use native local pointers.
84  *
85  *  Some operators (+/-) assume use the size of the underlying element. This
86  *  only works if the target applications is using the same target: it won't
87  *  work for example, when inspecting a 32 bit application from a 64 bit
88  *  model-checker.
89  *
90  *  We do not actually store the target address space because we can
91  *  always detect it in context. This way `RemotePtr` is as efficient
92  *  as a `uint64_t`.
93  */
94 template<class T> class RemotePtr {
95   std::uint64_t address_;
96 public:
97   RemotePtr() : address_(0) {}
98   RemotePtr(std::uint64_t address) : address_(address) {}
99   RemotePtr(T* address) : address_((std::uintptr_t)address) {}
100   RemotePtr(Remote<T*> p) : RemotePtr(*p.getBuffer()) {}
101   std::uint64_t address() const { return address_; }
102
103   /** Turn into a local pointer
104    *
105    (if the remote process is not, in fact, remote) */
106   T* local() const { return (T*) address_; }
107
108   operator bool() const
109   {
110     return address_;
111   }
112   bool operator!() const
113   {
114     return !address_;
115   }
116   operator RemotePtr<void>() const
117   {
118     return RemotePtr<void>(address_);
119   }
120   RemotePtr<T> operator+(std::uint64_t n) const
121   {
122     return RemotePtr<T>(address_ + n * sizeof(T));
123   }
124   RemotePtr<T> operator-(std::uint64_t n) const
125   {
126     return RemotePtr<T>(address_ - n * sizeof(T));
127   }
128   RemotePtr<T>& operator+=(std::uint64_t n)
129   {
130     address_ += n * sizeof(T);
131     return *this;
132   }
133   RemotePtr<T>& operator-=(std::uint64_t n)
134   {
135     address_ -= n * sizeof(T);
136     return *this;
137   }
138 };
139
140 template<class X, class Y>
141 bool operator<(RemotePtr<X> const& x, RemotePtr<Y> const& y)
142 {
143   return x.address() < y.address();
144 }
145
146 template<class X, class Y>
147 bool operator>(RemotePtr<X> const& x, RemotePtr<Y> const& y)
148 {
149   return x.address() > y.address();
150 }
151
152 template<class X, class Y>
153 bool operator>=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
154 {
155   return x.address() >= y.address();
156 }
157
158 template<class X, class Y>
159 bool operator<=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
160 {
161   return x.address() <= y.address();
162 }
163
164 template<class X, class Y>
165 bool operator==(RemotePtr<X> const& x, RemotePtr<Y> const& y)
166 {
167   return x.address() == y.address();
168 }
169
170 template<class X, class Y>
171 bool operator!=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
172 {
173   return x.address() != y.address();
174 }
175
176 template<class T> inline
177 RemotePtr<T> remote(T *p)
178 {
179   return RemotePtr<T>(p);
180 }
181
182 template<class T=void> inline
183 RemotePtr<T> remote(uint64_t p)
184 {
185   return RemotePtr<T>(p);
186 }
187
188 }
189 }
190
191 #endif