OLD | NEW |
| (Empty) |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef MOJO_EDK_SYSTEM_MEMORY_H_ | |
6 #define MOJO_EDK_SYSTEM_MEMORY_H_ | |
7 | |
8 #include <stddef.h> | |
9 #include <stdint.h> | |
10 #include <string.h> // For |memcpy()|. | |
11 | |
12 #include "base/macros.h" | |
13 #include "base/memory/scoped_ptr.h" | |
14 #include "mojo/edk/system/system_impl_export.h" | |
15 #include "mojo/public/c/system/macros.h" | |
16 | |
17 namespace mojo { | |
18 namespace system { | |
19 | |
20 namespace internal { | |
21 | |
22 // Removes |const| from |T| (available as |remove_const<T>::type|): | |
23 // TODO(vtl): Remove these once we have the C++11 |remove_const|. | |
24 template <typename T> | |
25 struct remove_const { | |
26 typedef T type; | |
27 }; | |
28 template <typename T> | |
29 struct remove_const<const T> { | |
30 typedef T type; | |
31 }; | |
32 | |
33 // Yields |(const) char| if |T| is |(const) void|, else |T|: | |
34 template <typename T> | |
35 struct VoidToChar { | |
36 typedef T type; | |
37 }; | |
38 template <> | |
39 struct VoidToChar<void> { | |
40 typedef char type; | |
41 }; | |
42 template <> | |
43 struct VoidToChar<const void> { | |
44 typedef const char type; | |
45 }; | |
46 | |
47 // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to | |
48 // a buffer of the given size and alignment (both in bytes). | |
49 template <size_t size, size_t alignment> | |
50 void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointer(const void* pointer); | |
51 | |
52 // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to | |
53 // a buffer of |count| elements of the given size and alignment (both in bytes). | |
54 template <size_t size, size_t alignment> | |
55 void MOJO_SYSTEM_IMPL_EXPORT | |
56 CheckUserPointerWithCount(const void* pointer, size_t count); | |
57 | |
58 // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to | |
59 // a buffer of the given size and alignment (both in bytes). | |
60 template <size_t alignment> | |
61 void MOJO_SYSTEM_IMPL_EXPORT | |
62 CheckUserPointerWithSize(const void* pointer, size_t size); | |
63 | |
64 } // namespace internal | |
65 | |
66 // Forward declarations so that they can be friended. | |
67 template <typename Type> | |
68 class UserPointerReader; | |
69 template <typename Type> | |
70 class UserPointerWriter; | |
71 template <typename Type> | |
72 class UserPointerReaderWriter; | |
73 template <class Options> | |
74 class UserOptionsReader; | |
75 | |
76 // Provides a convenient way to implicitly get null |UserPointer<Type>|s. | |
77 struct NullUserPointer {}; | |
78 | |
79 // Represents a user pointer to a single |Type| (which must be POD), for Mojo | |
80 // primitive parameters. | |
81 // | |
82 // Use a const |Type| for in parameters, and non-const |Type|s for out and | |
83 // in-out parameters (in which case the |Put()| method is available). | |
84 template <typename Type> | |
85 class UserPointer { | |
86 private: | |
87 typedef typename internal::VoidToChar<Type>::type NonVoidType; | |
88 | |
89 public: | |
90 // Instead of explicitly using these constructors, you can often use | |
91 // |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common | |
92 // exception is when you have, e.g., a |char*| and want to get a | |
93 // |UserPointer<void>|.) | |
94 UserPointer() : pointer_(nullptr) {} | |
95 explicit UserPointer(Type* pointer) : pointer_(pointer) {} | |
96 // Allow implicit conversion from the "null user pointer". | |
97 UserPointer(NullUserPointer) : pointer_(nullptr) {} | |
98 ~UserPointer() {} | |
99 | |
100 // Allow assignment from the "null user pointer". | |
101 UserPointer<Type>& operator=(NullUserPointer) { | |
102 pointer_ = nullptr; | |
103 return *this; | |
104 } | |
105 | |
106 // Allow conversion to a "non-const" |UserPointer|. | |
107 operator UserPointer<const Type>() const { | |
108 return UserPointer<const Type>(pointer_); | |
109 } | |
110 | |
111 bool IsNull() const { return !pointer_; } | |
112 | |
113 // "Reinterpret casts" to a |UserPointer<ToType>|. | |
114 template <typename ToType> | |
115 UserPointer<ToType> ReinterpretCast() const { | |
116 return UserPointer<ToType>(reinterpret_cast<ToType*>(pointer_)); | |
117 } | |
118 | |
119 // Checks that this pointer points to a valid |Type| in the same way as | |
120 // |Get()| and |Put()|. | |
121 // TODO(vtl): Logically, there should be separate read checks and write | |
122 // checks. | |
123 void Check() const { | |
124 internal::CheckUserPointer<sizeof(NonVoidType), MOJO_ALIGNOF(NonVoidType)>( | |
125 pointer_); | |
126 } | |
127 | |
128 // Checks that this pointer points to a valid array (of type |Type|, or just a | |
129 // buffer if |Type| is |void| or |const void|) of |count| elements (or bytes | |
130 // if |Type| is |void| or |const void|) in the same way as |GetArray()| and | |
131 // |PutArray()|. | |
132 // TODO(vtl): Logically, there should be separate read checks and write | |
133 // checks. | |
134 // TODO(vtl): Switch more things to use this. | |
135 void CheckArray(size_t count) const { | |
136 internal::CheckUserPointerWithCount<sizeof(NonVoidType), | |
137 MOJO_ALIGNOF(NonVoidType)>(pointer_, | |
138 count); | |
139 } | |
140 | |
141 // Gets the value (of type |Type|, or a |char| if |Type| is |void|) pointed to | |
142 // by this user pointer. Use this when you'd use the rvalue |*user_pointer|, | |
143 // but be aware that this may be costly -- so if the value will be used | |
144 // multiple times, you should save it. | |
145 // | |
146 // (We want to force a copy here, so return |Type| not |const Type&|.) | |
147 NonVoidType Get() const { | |
148 Check(); | |
149 internal::CheckUserPointer<sizeof(NonVoidType), MOJO_ALIGNOF(NonVoidType)>( | |
150 pointer_); | |
151 return *pointer_; | |
152 } | |
153 | |
154 // Gets an array (of type |Type|, or just a buffer if |Type| is |void| or | |
155 // |const void|) of |count| elements (or bytes if |Type| is |void| or |const | |
156 // void|) from the location pointed to by this user pointer. Use this when | |
157 // you'd do something like |memcpy(destination, user_pointer, count * | |
158 // sizeof(Type)|. | |
159 void GetArray(typename internal::remove_const<Type>::type* destination, | |
160 size_t count) const { | |
161 CheckArray(count); | |
162 memcpy(destination, pointer_, count * sizeof(NonVoidType)); | |
163 } | |
164 | |
165 // Puts a value (of type |Type|, or of type |char| if |Type| is |void|) to the | |
166 // location pointed to by this user pointer. Use this when you'd use the | |
167 // lvalue |*user_pointer|. Since this may be costly, you should avoid using | |
168 // this (for the same user pointer) more than once. | |
169 // | |
170 // Note: This |Put()| method is not valid when |T| is const, e.g., |const | |
171 // uint32_t|, but it's okay to include them so long as this template is only | |
172 // implicitly instantiated (see 14.7.1 of the C++11 standard) and not | |
173 // explicitly instantiated. (On implicit instantiation, only the declarations | |
174 // need be valid, not the definitions.) | |
175 // | |
176 // In C++11, we could do something like: | |
177 // template <typename _Type = Type> | |
178 // typename enable_if<!is_const<_Type>::value && | |
179 // !is_void<_Type>::value>::type Put( | |
180 // const _Type& value) { ... } | |
181 // (which obviously be correct), but C++03 doesn't allow default function | |
182 // template arguments. | |
183 void Put(const NonVoidType& value) { | |
184 Check(); | |
185 *pointer_ = value; | |
186 } | |
187 | |
188 // Puts an array (of type |Type|, or just a buffer if |Type| is |void|) with | |
189 // |count| elements (or bytes |Type| is |void|) to the location pointed to by | |
190 // this user pointer. Use this when you'd do something like | |
191 // |memcpy(user_pointer, source, count * sizeof(Type))|. | |
192 // | |
193 // Note: The same comments about the validity of |Put()| (except for the part | |
194 // about |void|) apply here. | |
195 void PutArray(const Type* source, size_t count) { | |
196 CheckArray(count); | |
197 memcpy(pointer_, source, count * sizeof(NonVoidType)); | |
198 } | |
199 | |
200 // Gets a |UserPointer| at offset |i| (in |Type|s) relative to this. | |
201 UserPointer At(size_t i) const { | |
202 return UserPointer( | |
203 static_cast<Type*>(static_cast<NonVoidType*>(pointer_) + i)); | |
204 } | |
205 | |
206 // Gets the value of the |UserPointer| as a |uintptr_t|. This should not be | |
207 // casted back to a pointer (and dereferenced), but may be used as a key for | |
208 // lookup or passed back to the user. | |
209 uintptr_t GetPointerValue() const { | |
210 return reinterpret_cast<uintptr_t>(pointer_); | |
211 } | |
212 | |
213 // These provides safe (read-only/write-only/read-and-write) access to a | |
214 // |UserPointer<Type>| (probably pointing to an array) using just an ordinary | |
215 // pointer (obtained via |GetPointer()|). | |
216 // | |
217 // The memory returned by |GetPointer()| may be a copy of the original user | |
218 // memory, but should be modified only if the user is intended to eventually | |
219 // see the change.) If any changes are made, |Commit()| should be called to | |
220 // guarantee that the changes are written back to user memory (it may be | |
221 // called multiple times). | |
222 // | |
223 // Note: These classes are designed to allow fast, unsafe implementations (in | |
224 // which |GetPointer()| just returns the user pointer) if desired. Thus if | |
225 // |Commit()| is *not* called, changes may or may not be made visible to the | |
226 // user. | |
227 // | |
228 // Use these classes in the following way: | |
229 // | |
230 // MojoResult Core::PutFoos(UserPointer<const uint32_t> foos, | |
231 // uint32_t num_foos) { | |
232 // UserPointer<const uint32_t>::Reader foos_reader(foos, num_foos); | |
233 // return PutFoosImpl(foos_reader.GetPointer(), num_foos); | |
234 // } | |
235 // | |
236 // MojoResult Core::GetFoos(UserPointer<uint32_t> foos, | |
237 // uint32_t num_foos) { | |
238 // UserPointer<uint32_t>::Writer foos_writer(foos, num_foos); | |
239 // MojoResult rv = GetFoosImpl(foos.GetPointer(), num_foos); | |
240 // foos_writer.Commit(); | |
241 // return rv; | |
242 // } | |
243 // | |
244 // TODO(vtl): Possibly, since we're not really being safe, we should just not | |
245 // copy for Release builds. | |
246 typedef UserPointerReader<Type> Reader; | |
247 typedef UserPointerWriter<Type> Writer; | |
248 typedef UserPointerReaderWriter<Type> ReaderWriter; | |
249 | |
250 private: | |
251 friend class UserPointerReader<Type>; | |
252 friend class UserPointerReader<const Type>; | |
253 friend class UserPointerWriter<Type>; | |
254 friend class UserPointerReaderWriter<Type>; | |
255 template <class Options> | |
256 friend class UserOptionsReader; | |
257 | |
258 Type* pointer_; | |
259 // Allow copy and assignment. | |
260 }; | |
261 | |
262 // Provides a convenient way to make a |UserPointer<Type>|. | |
263 template <typename Type> | |
264 inline UserPointer<Type> MakeUserPointer(Type* pointer) { | |
265 return UserPointer<Type>(pointer); | |
266 } | |
267 | |
268 // Implementation of |UserPointer<Type>::Reader|. | |
269 template <typename Type> | |
270 class UserPointerReader { | |
271 private: | |
272 typedef typename internal::remove_const<Type>::type TypeNoConst; | |
273 | |
274 public: | |
275 // Note: If |count| is zero, |GetPointer()| will always return null. | |
276 UserPointerReader(UserPointer<const Type> user_pointer, size_t count) { | |
277 Init(user_pointer.pointer_, count, true); | |
278 } | |
279 UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) { | |
280 Init(user_pointer.pointer_, count, true); | |
281 } | |
282 | |
283 const Type* GetPointer() const { return buffer_.get(); } | |
284 | |
285 private: | |
286 template <class Options> | |
287 friend class UserOptionsReader; | |
288 | |
289 struct NoCheck {}; | |
290 UserPointerReader(NoCheck, | |
291 UserPointer<const Type> user_pointer, | |
292 size_t count) { | |
293 Init(user_pointer.pointer_, count, false); | |
294 } | |
295 | |
296 void Init(const Type* user_pointer, size_t count, bool check) { | |
297 if (count == 0) | |
298 return; | |
299 | |
300 if (check) { | |
301 internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( | |
302 user_pointer, count); | |
303 } | |
304 buffer_.reset(new TypeNoConst[count]); | |
305 memcpy(buffer_.get(), user_pointer, count * sizeof(Type)); | |
306 } | |
307 | |
308 scoped_ptr<TypeNoConst[]> buffer_; | |
309 | |
310 DISALLOW_COPY_AND_ASSIGN(UserPointerReader); | |
311 }; | |
312 | |
313 // Implementation of |UserPointer<Type>::Writer|. | |
314 template <typename Type> | |
315 class UserPointerWriter { | |
316 public: | |
317 // Note: If |count| is zero, |GetPointer()| will always return null. | |
318 UserPointerWriter(UserPointer<Type> user_pointer, size_t count) | |
319 : user_pointer_(user_pointer), count_(count) { | |
320 if (count_ > 0) { | |
321 buffer_.reset(new Type[count_]); | |
322 memset(buffer_.get(), 0, count_ * sizeof(Type)); | |
323 } | |
324 } | |
325 | |
326 Type* GetPointer() const { return buffer_.get(); } | |
327 | |
328 void Commit() { | |
329 internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( | |
330 user_pointer_.pointer_, count_); | |
331 memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); | |
332 } | |
333 | |
334 private: | |
335 UserPointer<Type> user_pointer_; | |
336 size_t count_; | |
337 scoped_ptr<Type[]> buffer_; | |
338 | |
339 DISALLOW_COPY_AND_ASSIGN(UserPointerWriter); | |
340 }; | |
341 | |
342 // Implementation of |UserPointer<Type>::ReaderWriter|. | |
343 template <typename Type> | |
344 class UserPointerReaderWriter { | |
345 public: | |
346 // Note: If |count| is zero, |GetPointer()| will always return null. | |
347 UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count) | |
348 : user_pointer_(user_pointer), count_(count) { | |
349 if (count_ > 0) { | |
350 internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( | |
351 user_pointer_.pointer_, count_); | |
352 buffer_.reset(new Type[count]); | |
353 memcpy(buffer_.get(), user_pointer.pointer_, count * sizeof(Type)); | |
354 } | |
355 } | |
356 | |
357 Type* GetPointer() const { return buffer_.get(); } | |
358 size_t GetCount() const { return count_; } | |
359 | |
360 void Commit() { | |
361 internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( | |
362 user_pointer_.pointer_, count_); | |
363 memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); | |
364 } | |
365 | |
366 private: | |
367 UserPointer<Type> user_pointer_; | |
368 size_t count_; | |
369 scoped_ptr<Type[]> buffer_; | |
370 | |
371 DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter); | |
372 }; | |
373 | |
374 } // namespace system | |
375 } // namespace mojo | |
376 | |
377 #endif // MOJO_EDK_SYSTEM_MEMORY_H_ | |
OLD | NEW |