| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MOJO_EDK_SYSTEM_MEMORY_H_ |
| #define MOJO_EDK_SYSTEM_MEMORY_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <string.h> // For |memcpy()|. |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "mojo/edk/system/system_impl_export.h" |
| #include "mojo/public/c/system/macros.h" |
| #include "mojo/public/cpp/system/macros.h" |
| |
| namespace mojo { |
| namespace system { |
| |
| namespace internal { |
| |
| // Removes |const| from |T| (available as |remove_const<T>::type|): |
| // TODO(vtl): Remove these once we have the C++11 |remove_const|. |
| template <typename T> |
| struct remove_const { |
| using type = T; |
| }; |
| template <typename T> |
| struct remove_const<const T> { |
| using type = T; |
| }; |
| |
| // Yields |(const) char| if |T| is |(const) void|, else |T|: |
| template <typename T> |
| struct VoidToChar { |
| using type = T; |
| }; |
| template <> |
| struct VoidToChar<void> { |
| using type = char; |
| }; |
| template <> |
| struct VoidToChar<const void> { |
| using type = const char; |
| }; |
| |
| // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to |
| // a buffer of the given size and alignment (both in bytes). |
| template <size_t size, size_t alignment> |
| void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointer(const void* pointer); |
| |
| // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to |
| // a buffer of |count| elements of the given size and alignment (both in bytes). |
| template <size_t size, size_t alignment> |
| void MOJO_SYSTEM_IMPL_EXPORT |
| CheckUserPointerWithCount(const void* pointer, size_t count); |
| |
| // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to |
| // a buffer of the given size and alignment (both in bytes). |
| template <size_t alignment> |
| void MOJO_SYSTEM_IMPL_EXPORT |
| CheckUserPointerWithSize(const void* pointer, size_t size); |
| |
| } // namespace internal |
| |
| // Forward declarations so that they can be friended. |
| template <typename Type> |
| class UserPointerReader; |
| template <typename Type> |
| class UserPointerWriter; |
| template <typename Type> |
| class UserPointerReaderWriter; |
| template <class Options> |
| class UserOptionsReader; |
| |
| // Provides a convenient way to implicitly get null |UserPointer<Type>|s. |
| struct NullUserPointer {}; |
| |
| // Represents a user pointer to a single |Type| (which must be POD), for Mojo |
| // primitive parameters. |
| // |
| // Use a const |Type| for in parameters, and non-const |Type|s for out and |
| // in-out parameters (in which case the |Put()| method is available). |
| template <typename Type> |
| class UserPointer { |
| private: |
| using NonVoidType = typename internal::VoidToChar<Type>::type; |
| |
| public: |
| // Instead of explicitly using these constructors, you can often use |
| // |MakeUserPointer()| (or |NullUserPointer()| for null pointers). (The common |
| // exception is when you have, e.g., a |char*| and want to get a |
| // |UserPointer<void>|.) |
| UserPointer() : pointer_(nullptr) {} |
| explicit UserPointer(Type* pointer) : pointer_(pointer) {} |
| // Allow implicit conversion from the "null user pointer". |
| UserPointer(NullUserPointer) : pointer_(nullptr) {} |
| ~UserPointer() {} |
| |
| // Allow assignment from the "null user pointer". |
| UserPointer<Type>& operator=(NullUserPointer) { |
| pointer_ = nullptr; |
| return *this; |
| } |
| |
| // Allow conversion to a "non-const" |UserPointer|. |
| operator UserPointer<const Type>() const { |
| return UserPointer<const Type>(pointer_); |
| } |
| |
| bool IsNull() const { return !pointer_; } |
| |
| // "Reinterpret casts" to a |UserPointer<ToType>|. |
| template <typename ToType> |
| UserPointer<ToType> ReinterpretCast() const { |
| return UserPointer<ToType>(reinterpret_cast<ToType*>(pointer_)); |
| } |
| |
| // Checks that this pointer points to a valid |Type| in the same way as |
| // |Get()| and |Put()|. |
| // TODO(vtl): Logically, there should be separate read checks and write |
| // checks. |
| void Check() const { |
| internal::CheckUserPointer<sizeof(NonVoidType), MOJO_ALIGNOF(NonVoidType)>( |
| pointer_); |
| } |
| |
| // Checks that this pointer points to a valid array (of type |Type|, or just a |
| // buffer if |Type| is |void| or |const void|) of |count| elements (or bytes |
| // if |Type| is |void| or |const void|) in the same way as |GetArray()| and |
| // |PutArray()|. |
| // TODO(vtl): Logically, there should be separate read checks and write |
| // checks. |
| // TODO(vtl): Switch more things to use this. |
| void CheckArray(size_t count) const { |
| internal::CheckUserPointerWithCount<sizeof(NonVoidType), |
| MOJO_ALIGNOF(NonVoidType)>(pointer_, |
| count); |
| } |
| |
| // Gets the value (of type |Type|, or a |char| if |Type| is |void|) pointed to |
| // by this user pointer. Use this when you'd use the rvalue |*user_pointer|, |
| // but be aware that this may be costly -- so if the value will be used |
| // multiple times, you should save it. |
| // |
| // (We want to force a copy here, so return |Type| not |const Type&|.) |
| NonVoidType Get() const { |
| Check(); |
| internal::CheckUserPointer<sizeof(NonVoidType), MOJO_ALIGNOF(NonVoidType)>( |
| pointer_); |
| return *pointer_; |
| } |
| |
| // Gets an array (of type |Type|, or just a buffer if |Type| is |void| or |
| // |const void|) of |count| elements (or bytes if |Type| is |void| or |const |
| // void|) from the location pointed to by this user pointer. Use this when |
| // you'd do something like |memcpy(destination, user_pointer, count * |
| // sizeof(Type)|. |
| void GetArray(typename internal::remove_const<Type>::type* destination, |
| size_t count) const { |
| CheckArray(count); |
| memcpy(destination, pointer_, count * sizeof(NonVoidType)); |
| } |
| |
| // Puts a value (of type |Type|, or of type |char| if |Type| is |void|) to the |
| // location pointed to by this user pointer. Use this when you'd use the |
| // lvalue |*user_pointer|. Since this may be costly, you should avoid using |
| // this (for the same user pointer) more than once. |
| // |
| // Note: This |Put()| method is not valid when |T| is const, e.g., |const |
| // uint32_t|, but it's okay to include them so long as this template is only |
| // implicitly instantiated (see 14.7.1 of the C++11 standard) and not |
| // explicitly instantiated. (On implicit instantiation, only the declarations |
| // need be valid, not the definitions.) |
| // |
| // In C++11, we could do something like: |
| // template <typename _Type = Type> |
| // typename enable_if<!is_const<_Type>::value && |
| // !is_void<_Type>::value>::type Put( |
| // const _Type& value) { ... } |
| // (which obviously be correct), but C++03 doesn't allow default function |
| // template arguments. |
| void Put(const NonVoidType& value) { |
| Check(); |
| *pointer_ = value; |
| } |
| |
| // Puts an array (of type |Type|, or just a buffer if |Type| is |void|) with |
| // |count| elements (or bytes |Type| is |void|) to the location pointed to by |
| // this user pointer. Use this when you'd do something like |
| // |memcpy(user_pointer, source, count * sizeof(Type))|. |
| // |
| // Note: The same comments about the validity of |Put()| (except for the part |
| // about |void|) apply here. |
| void PutArray(const Type* source, size_t count) { |
| CheckArray(count); |
| memcpy(pointer_, source, count * sizeof(NonVoidType)); |
| } |
| |
| // Gets a |UserPointer| at offset |i| (in |Type|s) relative to this. |
| UserPointer At(size_t i) const { |
| return UserPointer( |
| static_cast<Type*>(static_cast<NonVoidType*>(pointer_) + i)); |
| } |
| |
| // Gets the value of the |UserPointer| as a |uintptr_t|. This should not be |
| // casted back to a pointer (and dereferenced), but may be used as a key for |
| // lookup or passed back to the user. |
| uintptr_t GetPointerValue() const { |
| return reinterpret_cast<uintptr_t>(pointer_); |
| } |
| |
| // These provides safe (read-only/write-only/read-and-write) access to a |
| // |UserPointer<Type>| (probably pointing to an array) using just an ordinary |
| // pointer (obtained via |GetPointer()|). |
| // |
| // The memory returned by |GetPointer()| may be a copy of the original user |
| // memory, but should be modified only if the user is intended to eventually |
| // see the change.) If any changes are made, |Commit()| should be called to |
| // guarantee that the changes are written back to user memory (it may be |
| // called multiple times). |
| // |
| // Note: These classes are designed to allow fast, unsafe implementations (in |
| // which |GetPointer()| just returns the user pointer) if desired. Thus if |
| // |Commit()| is *not* called, changes may or may not be made visible to the |
| // user. |
| // |
| // Use these classes in the following way: |
| // |
| // MojoResult Core::PutFoos(UserPointer<const uint32_t> foos, |
| // uint32_t num_foos) { |
| // UserPointer<const uint32_t>::Reader foos_reader(foos, num_foos); |
| // return PutFoosImpl(foos_reader.GetPointer(), num_foos); |
| // } |
| // |
| // MojoResult Core::GetFoos(UserPointer<uint32_t> foos, |
| // uint32_t num_foos) { |
| // UserPointer<uint32_t>::Writer foos_writer(foos, num_foos); |
| // MojoResult rv = GetFoosImpl(foos.GetPointer(), num_foos); |
| // foos_writer.Commit(); |
| // return rv; |
| // } |
| // |
| // TODO(vtl): Possibly, since we're not really being safe, we should just not |
| // copy for Release builds. |
| using Reader = UserPointerReader<Type>; |
| using Writer = UserPointerWriter<Type>; |
| using ReaderWriter = UserPointerReaderWriter<Type>; |
| |
| private: |
| friend class UserPointerReader<Type>; |
| friend class UserPointerReader<const Type>; |
| friend class UserPointerWriter<Type>; |
| friend class UserPointerReaderWriter<Type>; |
| template <class Options> |
| friend class UserOptionsReader; |
| |
| Type* pointer_; |
| // Allow copy and assignment. |
| }; |
| |
| // Provides a convenient way to make a |UserPointer<Type>|. |
| template <typename Type> |
| inline UserPointer<Type> MakeUserPointer(Type* pointer) { |
| return UserPointer<Type>(pointer); |
| } |
| |
| // Implementation of |UserPointer<Type>::Reader|. |
| template <typename Type> |
| class UserPointerReader { |
| private: |
| using TypeNoConst = typename internal::remove_const<Type>::type; |
| |
| public: |
| // Note: If |count| is zero, |GetPointer()| will always return null. |
| UserPointerReader(UserPointer<const Type> user_pointer, size_t count) { |
| Init(user_pointer.pointer_, count, true); |
| } |
| UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) { |
| Init(user_pointer.pointer_, count, true); |
| } |
| |
| const Type* GetPointer() const { return buffer_.get(); } |
| |
| private: |
| template <class Options> |
| friend class UserOptionsReader; |
| |
| struct NoCheck {}; |
| UserPointerReader(NoCheck, |
| UserPointer<const Type> user_pointer, |
| size_t count) { |
| Init(user_pointer.pointer_, count, false); |
| } |
| |
| void Init(const Type* user_pointer, size_t count, bool check) { |
| if (count == 0) |
| return; |
| |
| if (check) { |
| internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( |
| user_pointer, count); |
| } |
| buffer_.reset(new TypeNoConst[count]); |
| memcpy(buffer_.get(), user_pointer, count * sizeof(Type)); |
| } |
| |
| scoped_ptr<TypeNoConst[]> buffer_; |
| |
| MOJO_DISALLOW_COPY_AND_ASSIGN(UserPointerReader); |
| }; |
| |
| // Implementation of |UserPointer<Type>::Writer|. |
| template <typename Type> |
| class UserPointerWriter { |
| public: |
| // Note: If |count| is zero, |GetPointer()| will always return null. |
| UserPointerWriter(UserPointer<Type> user_pointer, size_t count) |
| : user_pointer_(user_pointer), count_(count) { |
| if (count_ > 0) { |
| buffer_.reset(new Type[count_]); |
| memset(buffer_.get(), 0, count_ * sizeof(Type)); |
| } |
| } |
| |
| Type* GetPointer() const { return buffer_.get(); } |
| |
| void Commit() { |
| internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( |
| user_pointer_.pointer_, count_); |
| memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); |
| } |
| |
| private: |
| UserPointer<Type> user_pointer_; |
| size_t count_; |
| scoped_ptr<Type[]> buffer_; |
| |
| MOJO_DISALLOW_COPY_AND_ASSIGN(UserPointerWriter); |
| }; |
| |
| // Implementation of |UserPointer<Type>::ReaderWriter|. |
| template <typename Type> |
| class UserPointerReaderWriter { |
| public: |
| // Note: If |count| is zero, |GetPointer()| will always return null. |
| UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count) |
| : user_pointer_(user_pointer), count_(count) { |
| if (count_ > 0) { |
| internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( |
| user_pointer_.pointer_, count_); |
| buffer_.reset(new Type[count]); |
| memcpy(buffer_.get(), user_pointer.pointer_, count * sizeof(Type)); |
| } |
| } |
| |
| Type* GetPointer() const { return buffer_.get(); } |
| size_t GetCount() const { return count_; } |
| |
| void Commit() { |
| internal::CheckUserPointerWithCount<sizeof(Type), MOJO_ALIGNOF(Type)>( |
| user_pointer_.pointer_, count_); |
| memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); |
| } |
| |
| private: |
| UserPointer<Type> user_pointer_; |
| size_t count_; |
| scoped_ptr<Type[]> buffer_; |
| |
| MOJO_DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter); |
| }; |
| |
| } // namespace system |
| } // namespace mojo |
| |
| #endif // MOJO_EDK_SYSTEM_MEMORY_H_ |