| Index: mojo/system/memory.h
|
| diff --git a/mojo/system/memory.h b/mojo/system/memory.h
|
| index 96f800ee15dae7b5b2c59c8c23fb8ca1c008055c..e19bfa870366852cf3fc88f424d8bd11ce67ee80 100644
|
| --- a/mojo/system/memory.h
|
| +++ b/mojo/system/memory.h
|
| @@ -6,7 +6,11 @@
|
| #define MOJO_SYSTEM_MEMORY_H_
|
|
|
| #include <stddef.h>
|
| +#include <stdint.h>
|
| +#include <string.h> // 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"
|
|
|
| @@ -15,6 +19,26 @@ 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 { typedef T type; };
|
| +template <typename T> struct remove_const<const T> { typedef T type; };
|
| +
|
| +// Yields |(const) char| if |T| is |(const) void|, else |T|:
|
| +template <typename T> struct VoidToChar { typedef T type; };
|
| +template <> struct VoidToChar<void> { typedef char type; };
|
| +template <> struct VoidToChar<const void> { typedef const char type; };
|
| +
|
| +template <size_t size, size_t alignment>
|
| +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerHelper(const void* pointer);
|
| +
|
| +template <size_t size, size_t alignment>
|
| +void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointerWithCountHelper(
|
| + const void* pointer,
|
| + size_t count);
|
| +
|
| +// TODO(vtl): Delete all the |Verify...()| things (and replace them with
|
| +// |Check...()|.
|
| template <size_t size, size_t alignment>
|
| bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer);
|
|
|
| @@ -26,6 +50,11 @@ bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper(
|
|
|
| } // 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;
|
| +
|
| // Verify (insofar as possible/necessary) that a |T| can be read from the user
|
| // |pointer|.
|
| template <typename T>
|
| @@ -50,6 +79,247 @@ template <size_t alignment>
|
| bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer,
|
| size_t size);
|
|
|
| +// 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 {
|
| + 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_(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<Type>& operator=(NullUserPointer) {
|
| + pointer_ = NULL;
|
| + return *this;
|
| + }
|
| +
|
| + // Allow conversion to a "non-const" |UserPointer|.
|
| + operator UserPointer<const Type>() const {
|
| + return UserPointer<const Type>(pointer_);
|
| + }
|
| +
|
| + bool IsNull() const {
|
| + return !pointer_;
|
| + }
|
| +
|
| + // We want to force a copy here, so return |Type| not |const Type&|.
|
| + Type Get() const {
|
| + internal::CheckUserPointerHelper<sizeof(Type),
|
| + MOJO_ALIGNOF(Type)>(pointer_);
|
| + return *pointer_;
|
| + }
|
| +
|
| + // 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.)
|
| + //
|
| + // If |Type| is |void|, we "convert" it to |char|, so that it makes sense.
|
| + // (Otherwise, we'd need a suitable specialization to exclude |Put()|.)
|
| + //
|
| + // 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 typename internal::VoidToChar<Type>::type& value) {
|
| + internal::CheckUserPointerHelper<sizeof(Type),
|
| + MOJO_ALIGNOF(Type)>(pointer_);
|
| + *pointer_ = value;
|
| + }
|
| +
|
| + UserPointer At(size_t i) const {
|
| + return UserPointer(pointer_ + i);
|
| + }
|
| +
|
| + // TODO(vtl): This is temporary. Get rid of this. (We should pass
|
| + // |UserPointer<>|s along appropriately, or access data in a safe way
|
| + // everywhere.)
|
| + Type* GetPointerUnsafe() const {
|
| + return 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.
|
| + typedef UserPointerReader<Type> Reader;
|
| + typedef UserPointerWriter<Type> Writer;
|
| + typedef UserPointerReaderWriter<Type> ReaderWriter;
|
| +
|
| + private:
|
| + friend class UserPointerReader<Type>;
|
| + friend class UserPointerWriter<Type>;
|
| + friend class UserPointerReaderWriter<Type>;
|
| +
|
| + 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:
|
| + typedef typename internal::remove_const<Type>::type TypeNoConst;
|
| +
|
| + public:
|
| + UserPointerReader(UserPointer<const Type> user_pointer, size_t count) {
|
| + Init(user_pointer.pointer_, count);
|
| + }
|
| + UserPointerReader(UserPointer<TypeNoConst> user_pointer, size_t count) {
|
| + Init(user_pointer.pointer_, count);
|
| + }
|
| +
|
| + const Type* GetPointer() const { return buffer_.get(); }
|
| +
|
| + private:
|
| + void Init(const Type* user_pointer, size_t count) {
|
| + internal::CheckUserPointerWithCountHelper<
|
| + 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_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UserPointerReader);
|
| +};
|
| +
|
| +// Implementation of |UserPointer<Type>::Writer|.
|
| +template <typename Type>
|
| +class UserPointerWriter {
|
| + public:
|
| + UserPointerWriter(UserPointer<Type> user_pointer, size_t count)
|
| + : user_pointer_(user_pointer),
|
| + count_(count) {
|
| + buffer_.reset(new Type[count_]);
|
| + memset(buffer_.get(), 0, count_ * sizeof(Type));
|
| + }
|
| +
|
| + Type* GetPointer() const { return buffer_.get(); }
|
| +
|
| + void Commit() {
|
| + internal::CheckUserPointerWithCountHelper<
|
| + 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_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UserPointerWriter);
|
| +};
|
| +
|
| +// Implementation of |UserPointer<Type>::ReaderWriter|.
|
| +template <typename Type>
|
| +class UserPointerReaderWriter {
|
| + public:
|
| + UserPointerReaderWriter(UserPointer<Type> user_pointer, size_t count)
|
| + : user_pointer_(user_pointer),
|
| + count_(count) {
|
| + internal::CheckUserPointerWithCountHelper<
|
| + 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::CheckUserPointerWithCountHelper<
|
| + 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_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter);
|
| +};
|
| +
|
| +// Represents a user pointer that will never be dereferenced by the system. The
|
| +// pointer value (i.e., the address) may be as a key for lookup, or may be a
|
| +// value that is only passed to the user at some point.
|
| +template <typename Type>
|
| +class UserPointerValue {
|
| + public:
|
| + UserPointerValue() : pointer_() {}
|
| + explicit UserPointerValue(Type* pointer) : pointer_(pointer) {}
|
| + ~UserPointerValue() {}
|
| +
|
| + // Returns the *value* of the pointer, which shouldn't be cast back to a
|
| + // pointer and dereferenced.
|
| + uintptr_t GetValue() const {
|
| + return reinterpret_cast<uintptr_t>(pointer_);
|
| + }
|
| +
|
| + private:
|
| + Type* pointer_;
|
| + // Allow copy and assignment.
|
| +};
|
| +
|
| +// Provides a convenient way to make a |UserPointerValue<Type>|.
|
| +template <typename Type>
|
| +inline UserPointerValue<Type> MakeUserPointerValue(Type* pointer) {
|
| + return UserPointerValue<Type>(pointer);
|
| +}
|
| +
|
| } // namespace system
|
| } // namespace mojo
|
|
|
|
|