Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / system / memory.h
index 96f800e..acbbb54 100644 (file)
@@ -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,40 +19,357 @@ 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;
+};
+
+// 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>
-bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerHelper(const void* pointer);
+void MOJO_SYSTEM_IMPL_EXPORT CheckUserPointer(const void* pointer);
 
-// Note: This is also used by options_validation.h.
+// 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>
-bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithCountHelper(
-    const void* pointer,
-    size_t count);
+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
 
-// Verify (insofar as possible/necessary) that a |T| can be read from the user
-// |pointer|.
-template <typename T>
-bool VerifyUserPointer(const T* pointer) {
-  return internal::VerifyUserPointerHelper<sizeof(T), MOJO_ALIGNOF(T)>(pointer);
-}
+// 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;
 
-// Verify (insofar as possible/necessary) that |count| |T|s can be read from the
-// user |pointer|; |count| may be zero. (This is done carefully since |count *
-// sizeof(T)| may overflow a |size_t|.)
-template <typename T>
-bool VerifyUserPointerWithCount(const T* pointer, size_t count) {
-  return internal::VerifyUserPointerWithCountHelper<sizeof(T),
-                                                    MOJO_ALIGNOF(T)>(pointer,
-                                                                     count);
+// 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:
+  typedef typename internal::VoidToChar<Type>::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<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.
+  typedef UserPointerReader<Type> Reader;
+  typedef UserPointerWriter<Type> Writer;
+  typedef UserPointerReaderWriter<Type> ReaderWriter;
+
+ 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);
 }
 
-// Verify that |size| bytes (which may be zero) can be read from the user
-// |pointer|, and that |pointer| has the specified |alignment| (if |size| is
-// nonzero).
-template <size_t alignment>
-bool MOJO_SYSTEM_IMPL_EXPORT VerifyUserPointerWithSize(const void* pointer,
-                                                       size_t size);
+// Implementation of |UserPointer<Type>::Reader|.
+template <typename Type>
+class UserPointerReader {
+ private:
+  typedef typename internal::remove_const<Type>::type TypeNoConst;
+
+ 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_;
+
+  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_;
+
+  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_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserPointerReaderWriter);
+};
 
 }  // namespace system
 }  // namespace mojo