// 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_SYSTEM_MEMORY_H_ #define MOJO_SYSTEM_MEMORY_H_ #include #include #include // For |memcpy()|. #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "mojo/public/c/system/macros.h" #include "mojo/system/system_impl_export.h" namespace mojo { namespace system { namespace internal { // Removes |const| from |T| (available as |remove_const::type|): // TODO(vtl): Remove these once we have the C++11 |remove_const|. template struct remove_const { typedef T type; }; template struct remove_const { typedef T type; }; // Yields |(const) char| if |T| is |(const) void|, else |T|: template struct VoidToChar { typedef T type; }; template <> struct VoidToChar { typedef char type; }; template <> struct VoidToChar { typedef const char type; }; // Checks (insofar as appropriate/possible) that |pointer| is a valid pointer to // a buffer of the given size and alignment (both in bytes). template 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 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 void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithSize(const void* pointer, size_t size); } // namespace internal // Forward declarations so that they can be friended. template class UserPointerReader; template class UserPointerWriter; template class UserPointerReaderWriter; template class UserOptionsReader; // Provides a convenient way to implicitly get null |UserPointer|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 class UserPointer { private: typedef typename internal::VoidToChar::type NonVoidType; 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|.) UserPointer() : pointer_(NULL) {} explicit UserPointer(Type* pointer) : pointer_(pointer) {} // Allow implicit conversion from the "null user pointer". UserPointer(NullUserPointer) : pointer_(NULL) {} ~UserPointer() {} // Allow assignment from the "null user pointer". UserPointer& operator=(NullUserPointer) { pointer_ = NULL; return *this; } // Allow conversion to a "non-const" |UserPointer|. operator UserPointer() const { return UserPointer(pointer_); } bool IsNull() const { return !pointer_; } // "Reinterpret casts" to a |UserPointer|. template UserPointer ReinterpretCast() const { return UserPointer(reinterpret_cast(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( 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(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( 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* 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 enable_if::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(static_cast(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(pointer_); } // These provides safe (read-only/write-only/read-and-write) access to a // |UserPointer| (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 foos, // uint32_t num_foos) { // UserPointer::Reader foos_reader(foos, num_foos); // return PutFoosImpl(foos_reader.GetPointer(), num_foos); // } // // MojoResult Core::GetFoos(UserPointer foos, // uint32_t num_foos) { // UserPointer::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. typedef UserPointerReader Reader; typedef UserPointerWriter Writer; typedef UserPointerReaderWriter ReaderWriter; private: friend class UserPointerReader; friend class UserPointerReader; friend class UserPointerWriter; friend class UserPointerReaderWriter; template friend class UserOptionsReader; Type* pointer_; // Allow copy and assignment. }; // Provides a convenient way to make a |UserPointer|. template inline UserPointer MakeUserPointer(Type* pointer) { return UserPointer(pointer); } // Implementation of |UserPointer::Reader|. template class UserPointerReader { private: typedef typename internal::remove_const::type TypeNoConst; public: // Note: If |count| is zero, |GetPointer()| will always return null. UserPointerReader(UserPointer user_pointer, size_t count) { Init(user_pointer.pointer_, count, true); } UserPointerReader(UserPointer user_pointer, size_t count) { Init(user_pointer.pointer_, count, true); } const Type* GetPointer() const { return buffer_.get(); } private: template friend class UserOptionsReader; struct NoCheck {}; UserPointerReader(NoCheck, UserPointer 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( user_pointer, count); } buffer_.reset(new TypeNoConst[count]); memcpy(buffer_.get(), user_pointer, count * sizeof(Type)); } scoped_ptr buffer_; DISALLOW_COPY_AND_ASSIGN(UserPointerReader); }; // Implementation of |UserPointer::Writer|. template class UserPointerWriter { public: // Note: If |count| is zero, |GetPointer()| will always return null. UserPointerWriter(UserPointer 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( user_pointer_.pointer_, count_); memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); } private: UserPointer user_pointer_; size_t count_; scoped_ptr buffer_; DISALLOW_COPY_AND_ASSIGN(UserPointerWriter); }; // Implementation of |UserPointer::ReaderWriter|. template class UserPointerReaderWriter { public: // Note: If |count| is zero, |GetPointer()| will always return null. UserPointerReaderWriter(UserPointer user_pointer, size_t count) : user_pointer_(user_pointer), count_(count) { if (count_ > 0) { internal::CheckUserPointerWithCount( 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( user_pointer_.pointer_, count_); memcpy(user_pointer_.pointer_, buffer_.get(), count_ * sizeof(Type)); } private: UserPointer user_pointer_; size_t count_; scoped_ptr buffer_; DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter); }; } // namespace system } // namespace mojo #endif // MOJO_SYSTEM_MEMORY_H_