Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(887)

Unified Diff: mojo/public/bindings/test.cc

Issue 23913008: C++ bindings (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added BlahProxy Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/mojo.gyp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/public/bindings/test.cc
diff --git a/mojo/public/bindings/test.cc b/mojo/public/bindings/test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1322e40a7f344140b04ab1b527ee7b9176a5bcec
--- /dev/null
+++ b/mojo/public/bindings/test.cc
@@ -0,0 +1,651 @@
+/*
+// HYPOTHETICAL IDL:
+
+struct Bar {
+ alpha @0 :uint8;
+ beta @1 :uint8;
+ gamma @2 :uint8;
+};
+
+struct Foo {
+ x @0 :int32;
+ y @1 :int32;
+ a @2 :bool;
+ b @3 :bool;
+ c @4 :bool;
+ bar @5 :Bar;
+ extra_bars @7 :array(Bar) [optional];
+ data @6 :array(uint8);
+};
+
+interface Blah {
+ Frobinate @0 (foo @0 :Foo, baz @1 :bool);
+};
+
+*/
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <new>
+#include <vector>
+
+// This would be part of some header file we'd provide.
+
+typedef uint32_t Handle;
+
+struct Message {
+ uint32_t name;
+ uint8_t* data_start;
+ uint8_t* data_end;
+ Handle* handles_start;
+ Handle* handles_end;
+};
+
+struct MessageHeader {
+ uint32_t num_bytes;
+ uint32_t name;
+};
+
+struct StructHeader {
+ uint32_t num_bytes;
+ uint32_t num_fields;
+};
+
+struct ArrayHeader {
+ uint32_t num_bytes;
+ uint32_t num_elements;
+};
+
+template <typename T> class Array;
+
+template <typename T>
+union StructPointer {
+ uint64_t offset;
+ T* ptr;
+};
+
+template <typename T>
+union ArrayPointer {
+ uint64_t offset;
+ Array<T>* ptr;
+};
+
+inline void EncodePointer(void* address, uint64_t* offset) {
+ if (!address) {
+ *offset = 0;
+ return;
+ }
+ uint8_t* p_obj = reinterpret_cast<uint8_t*>(address);
+ uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset);
+ assert(p_obj > p_slot);
+ *offset = p_obj - p_slot;
+}
+
+template <typename T>
+inline void DecodePointer(uint64_t* offset, T** ptr) {
+ if (!*offset) {
+ *ptr = NULL;
+ return;
+ }
+ uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset);
+ *ptr = reinterpret_cast<T*>(p_slot + *offset);
piman 2013/09/25 17:26:25 Note: strict aliasing rules only allow reinterpret
+}
+
+template <typename T>
+struct ArrayTraits {
+ typedef T ElementType;
+
+ static T& ToElementRef(ElementType& e) { return e; }
+ static T const& ToElementConstRef(const ElementType& e) { return e; }
+
+ template <typename Allocator>
+ static void CloneElements(Allocator* allocator,
+ ArrayHeader* header,
+ ElementType* elements) {
+ }
+
+ static void EncodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ std::vector<Handle>* handles) {
+ }
+ static bool DecodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ const Message& message) {
+ return true;
+ }
+};
+
+template <typename P>
+struct ArrayTraits<P*> {
+ typedef StructPointer<P> ElementType;
+
+ static P*& ToElementRef(ElementType& e) { return e.ptr; }
+ static P* const& ToElementConstRef(const ElementType& e) { return e.ptr; }
+
+ template <typename Allocator>
+ static void CloneElements(Allocator* allocator,
+ ArrayHeader* header,
+ ElementType* elements) {
+ for (uint32_t i = 0; i < header->num_elements; ++i) {
+ if (elements[i].ptr)
+ elements[i].ptr = elements[i].ptr->Clone(allocator);
+ }
+ }
+
+ static void EncodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ std::vector<Handle>* handles) {
+ for (uint32_t i = 0; i < header->num_elements; ++i) {
+ if (elements[i].ptr)
+ elements[i].ptr->EncodePointersAndHandles(handles);
+ EncodePointer(elements[i].ptr, &elements[i].offset);
+ }
+ }
+ static bool DecodePointersAndHandles(ArrayHeader* header,
+ ElementType* elements,
+ const Message& message) {
+ for (uint32_t i = 0; i < header->num_elements; ++i) {
+ DecodePointer(&elements[i].offset, &elements[i].ptr);
+ if (elements[i].ptr)
+ elements[i].ptr->DecodePointersAndHandles(message);
+ }
+ return true;
+ }
+};
+
+template <typename T>
+class Array {
+ public:
+ explicit Array(size_t num_elements) {
+ // TODO: bools should get packed to a single bit?
+ header_.num_bytes =
+ sizeof(typename ArrayTraits<T>::ElementType) * num_elements +
+ sizeof(ArrayHeader);
+ header_.num_elements = num_elements;
+ }
+
+ template <typename Allocator>
+ Array<T>* Clone(Allocator* allocator) const {
+ Array<T>* array =
+ reinterpret_cast<Array<T>*>(allocator->AllocBytes(header_.num_bytes));
+ memcpy(array, this, header_.num_bytes);
+
+ ArrayTraits<T>::CloneElements(allocator, &array->header_, array->elements_);
+ return array;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ ArrayTraits<T>::EncodePointersAndHandles(&header_, elements_, handles);
+ }
+ bool DecodePointersAndHandles(const Message& message) {
+ return ArrayTraits<T>::DecodePointersAndHandles(&header_, elements_,
+ message);
+ }
+
+ size_t size() const { return header_.num_elements; }
+
+ T& at(size_t offset) {
+ return ArrayTraits<T>::ToElementRef(elements_[offset]);
+ }
+
+ const T& at(size_t offset) const {
+ return ArrayTraits<T>::ToElementConstRef(elements_[offset]);
+ }
+
+ T& operator[](size_t offset) {
+ return ArrayTraits<T>::ToElementRef(elements_[offset]);
+ }
+
+ const T& operator[](size_t offset) const {
+ return ArrayTraits<T>::ToElementConstRef(elements_[offset]);
+ }
+
+ private:
+ ArrayHeader header_;
+ typename ArrayTraits<T>::ElementType elements_[1]; // Extra elements follow.
+};
+
+// The following is a cheezy arena allocator.
+class Buffer {
+ public:
+ Buffer() : ptr_(NULL), size_(0) {
+ }
+ ~Buffer() { free(ptr_); }
+
+ const uint8_t* data() const { return ptr_; }
+ uint8_t* data() { return ptr_; }
+
+ size_t size() const { return size_; }
+
+ uint8_t* AllocBytes(size_t size) {
+ return Grow(size);
+ }
+
+ template <typename T>
+ T* Alloc() {
+ size_t size = sizeof(T);
+ return new (Grow(size)) T();
+ }
+
+ template <typename T>
+ Array<T>* AllocArray(size_t count) {
+ // (count - 1) because Array<T> has reserved space for the first element.
+ size_t size = sizeof(Array<T>) + sizeof(T) * (count - 1);
+ return new (Grow(size)) Array<T>(count);
+ }
+
+ private:
+ uint8_t* Grow(size_t delta) {
+ // TODO: Align allocations
+ size_t old_size = size_;
+ size_t new_size = old_size + delta;
+ ptr_ = static_cast<uint8_t*>(realloc(ptr_, old_size + delta));
+ size_ = new_size;
+ uint8_t* result = ptr_ + old_size;
+ memset(result, 0, delta);
+ return result;
+ }
+
+ uint8_t* ptr_;
+ size_t size_;
+
+ // NOT IMPLEMENTED
+ Buffer(const Buffer&);
+ void operator=(const Buffer&);
+};
+
+//----
+// Begin generated code.
+
+// What follows is class definitions corresponding to the structures indicated
+// by the IDL.
+
+class Bar {
+ public:
+ Bar() {
+ header_.num_bytes = sizeof(*this) + sizeof(StructHeader);
+ header_.num_fields = 3;
+ }
+
+ Bar* Clone(Buffer* buf) const {
+ Bar* bar = buf->Alloc<Bar>();
+ memcpy(bar, this, sizeof(*this));
+ return bar;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ }
+ bool DecodePointersAndHandles(const Message& message) {
+ return true;
+ }
+
+ void set_alpha(uint8_t alpha) { d_.alpha = alpha; }
+ void set_beta(uint8_t beta) { d_.beta = beta; }
+ void set_gamma(uint8_t gamma) { d_.gamma = gamma; }
+
+ uint8_t alpha() const { return d_.alpha; }
+ uint8_t beta() const { return d_.beta; }
+ uint8_t gamma() const { return d_.gamma; }
+
+ private:
+ StructHeader header_;
Hajime Morrita 2013/09/25 20:03:55 One possible alternative is to keep the message cl
+ struct {
+ uint8_t alpha;
+ uint8_t beta;
+ uint8_t gamma;
+ } d_;
+
+ ~Bar(); // NOT IMPLEMENTED
+};
+
+class Foo {
+ public:
+ Foo() {
+ header_.num_bytes = sizeof(*this) + sizeof(StructHeader);
+ header_.num_fields = 8;
+ }
+
+ Foo* Clone(Buffer* buf) const {
+ Foo* foo = buf->Alloc<Foo>();
+ memcpy(foo, this, sizeof(*this));
+
+ foo->set_bar(foo->bar()->Clone(buf));
+ foo->set_data(foo->data()->Clone(buf));
+ foo->set_extra_bars(foo->extra_bars()->Clone(buf));
+
+ return foo;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ if (d_.bar.ptr)
+ d_.bar.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.bar.ptr, &d_.bar.offset);
+
+ if (d_.data.ptr)
+ d_.data.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.data.ptr, &d_.data.offset);
+
+ if (d_.extra_bars.ptr)
+ d_.extra_bars.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.extra_bars.ptr, &d_.extra_bars.offset);
+ }
+
+ bool DecodePointersAndHandles(const Message& message) {
+ DecodePointer(&d_.bar.offset, &d_.bar.ptr);
+ if (d_.bar.ptr) {
+ if (!d_.bar.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+
+ DecodePointer(&d_.data.offset, &d_.data.ptr);
+ if (d_.data.ptr) {
+ if (!d_.data.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+
+ if (header_.num_fields >= 8) {
+ DecodePointer(&d_.extra_bars.offset, &d_.extra_bars.ptr);
+ if (d_.extra_bars.ptr) {
+ if (!d_.extra_bars.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+ }
+
+ // TODO: validate
+ return true;
+ }
+
+ void set_x(int32_t x) { d_.x = x; }
+ void set_y(int32_t y) { d_.y = y; }
+ void set_a(bool a) { d_.a = a; }
+ void set_b(bool b) { d_.b = b; }
+ void set_c(bool c) { d_.c = c; }
+ void set_bar(Bar* bar) { d_.bar.ptr = bar; }
+ void set_data(Array<uint8_t>* data) { d_.data.ptr = data; }
+ void set_extra_bars(Array<Bar*>* extra_bars) {
+ d_.extra_bars.ptr = extra_bars;
+ }
+
+ int32_t x() const { return d_.x; }
+ int32_t y() const { return d_.y; }
+ bool a() const { return d_.a; }
+ bool b() const { return d_.b; }
+ bool c() const { return d_.c; }
+ const Bar* bar() const { return d_.bar.ptr; }
+ const Array<uint8_t>* data() const { return d_.data.ptr; }
+ const Array<Bar*>* extra_bars() const {
+ // NOTE: extra_bars is an optional field!
+ return header_.num_fields >= 8 ? d_.extra_bars.ptr : NULL;
+ }
+
+ private:
+ StructHeader header_;
+ struct {
+ int32_t x;
+ int32_t y;
+ uint32_t a : 1;
+ uint32_t b : 1;
+ uint32_t c : 1;
+ StructPointer<Bar> bar;
+ ArrayPointer<uint8_t> data;
+ ArrayPointer<Bar*> extra_bars;
+ } d_;
+
+ ~Foo(); // NOT IMPLEMENTED
+};
+
+class Frobinate_Params {
+ public:
+ Frobinate_Params() {
+ header_.num_bytes = sizeof(*this) + sizeof(StructHeader);
+ header_.num_fields = 2;
+ }
+
+ void EncodePointersAndHandles(std::vector<Handle>* handles) {
+ if (d_.foo.ptr)
+ d_.foo.ptr->EncodePointersAndHandles(handles);
+ EncodePointer(d_.foo.ptr, &d_.foo.offset);
+ }
+ bool DecodePointersAndHandles(const Message& message) {
+ DecodePointer(&d_.foo.offset, &d_.foo.ptr);
+ if (d_.foo.ptr) {
+ if (!d_.foo.ptr->DecodePointersAndHandles(message))
+ return false;
+ }
+ // TODO: validate
+ return true;
+ }
+
+ void set_foo(Foo* foo) { d_.foo.ptr = foo; }
+ void set_baz(bool baz) { d_.baz = baz; }
+
+ const Foo* foo() const { return d_.foo.ptr; }
+ bool baz() const { return d_.baz; }
+
+ private:
+ StructHeader header_;
+ struct {
+ StructPointer<Foo> foo;
+ uint32_t baz : 1;
+ } d_;
+
+ ~Frobinate_Params(); // NOT IMPLEMENTED
+};
+
+const uint32_t kMessageID_Frobinate = 1;
+
+//----
+// The following code would also be generated by our bindings system.
+
+class Blah {
+ public:
+ virtual void Frobinate(const Foo* foo, bool baz) = 0;
+};
+
+class BlahStub : public Blah {
+ public:
+ bool OnMessageReceived(const Message& message) {
+ switch (message.name) {
+ case kMessageID_Frobinate: {
+ Frobinate_Params* params =
+ reinterpret_cast<Frobinate_Params*>(message.data_start);
+ if (!params->DecodePointersAndHandles(message))
+ return false;
+ Frobinate(params->foo(), params->baz());
+ break;
+ }
+ }
+ return true;
+ }
+};
+
+class BlahProxy : public Blah {
+ public:
+ virtual void SendMessage(const Message& message) = 0;
+
+ virtual void Frobinate(const Foo* foo, bool baz) {
+ Buffer buf;
+
+ // TODO: We should allocate the MessageHeader here to reserve space.
+ //MessageHeader* header = buf.Alloc<MessageHeader>();
+
+ // We now go about allocating the anonymous Frobinate_Params struct. It
+ // holds the parameters to the Frobinate message.
+ //
+ // Notice how foo is cloned. This causes a copy of foo to be generated
+ // within the same buffer as the Frobinate_Params struct. That's what we
+ // need in order to generate a continguous blob of message data.
+
+ Frobinate_Params* params = buf.Alloc<Frobinate_Params>();
+ params->set_foo(foo->Clone(&buf));
+ params->set_baz(baz);
+
+ // NOTE: If foo happened to be a graph with cycles, then Clone would not
+ // have returned.
+
+ // Last step before sending the message is to encode pointers and handles
+ // so that messages become hermetic. Pointers become offsets and handles
+ // becomes indices into the handles array.
+
+ std::vector<Handle> handles;
+ params->EncodePointersAndHandles(&handles);
+
+ Message message;
+ message.name = kMessageID_Frobinate;
+ message.data_start = buf.data();
+ message.data_end = buf.data() + buf.size();
+ message.handles_start = &handles[0];
+ message.handles_end = &handles[0] + handles.size();
+
+ SendMessage(message);
+ }
+};
+
+//----
+// User code goes here:
+
+static void PrintSpacer(int depth) {
+ for (int i = 0; i < depth; ++i)
+ printf(" ");
+}
+
+static void Print(int depth, const char* name, bool value) {
+ PrintSpacer(depth);
+ printf("%s: %s\n", name, value ? "true" : "false");
+}
+
+static void Print(int depth, const char* name, int32_t value) {
+ PrintSpacer(depth);
+ printf("%s: %d\n", name, value);
+}
+
+static void Print(int depth, const char* name, uint8_t value) {
+ PrintSpacer(depth);
+ printf("%s: %u\n", name, value);
+}
+
+template <typename T>
+static void Print(int depth, const char* name, const Array<T>* array) {
+ PrintSpacer(depth);
+ printf("%s: %p\n", name, array);
+ if (array) {
+ ++depth;
+ for (size_t i = 0; i < array->size(); ++i) {
+ char buf[32];
+ sprintf(buf, "%lu", i);
+ Print(depth, buf, array->at(i));
+ }
+ --depth;
+ }
+}
+
+static void Print(int depth, const char* name, const Bar* bar) {
+ PrintSpacer(depth);
+ printf("%s: %p\n", name, bar);
+ if (bar) {
+ ++depth;
+ Print(depth, "alpha", bar->alpha());
+ Print(depth, "beta", bar->beta());
+ Print(depth, "gamma", bar->gamma());
+ --depth;
+ }
+}
+
+static void Print(int depth, const char* name, const Foo* foo) {
+ PrintSpacer(depth);
+ printf("%s: %p\n", name, foo);
+ if (foo) {
+ ++depth;
+ Print(depth, "x", foo->x());
+ Print(depth, "y", foo->y());
+ Print(depth, "a", foo->a());
+ Print(depth, "b", foo->b());
+ Print(depth, "c", foo->c());
+ Print(depth, "bar", foo->bar());
+ Print(depth, "data", foo->data());
+ Print(depth, "extra_bars", foo->extra_bars());
+ --depth;
+ }
+}
+
+class BlahImpl : public BlahStub {
+ public:
+ virtual void Frobinate(const Foo* foo, bool baz) {
+ // Users code goes here to handle the incoming Frobinate message.
+ // We'll just dump the Foo structure and all of its members.
+
+ printf("Frobinate:\n");
+
+ int depth = 1;
+ Print(depth, "foo", foo);
+ Print(depth, "baz", baz);
+ }
+};
+
+//----
+
+class BlahProxyImpl : public BlahProxy {
+ public:
+ virtual void SendMessage(const Message& message) {
+ // Imagine some IPC happened here.
+
+ // In the receiving process, an implementation of BlahStub is known to the
+ // system. It receives the incoming message.
+ BlahImpl impl;
+ BlahStub* stub = &impl;
+
+ stub->OnMessageReceived(message);
+ }
+};
+
+int main() {
+ // User has a proxy to a Blah somehow.
+ Blah* blah = new BlahProxyImpl();
+
+ // User constructs a message to send.
+
+ // Notice that it doesn't matter in what order the structs / arrays are
+ // allocated. Here, the various members of Foo are allocated before Foo is
+ // allocated.
+
+ Buffer buf;
+
+ Bar* bar = buf.Alloc<Bar>();
+ bar->set_alpha(20);
+ bar->set_beta(40);
+ bar->set_gamma(60);
+
+ const size_t kNumDataElements = 10;
+ Array<uint8_t>* data = buf.AllocArray<uint8_t>(kNumDataElements);
+ for (size_t i = 0; i < kNumDataElements; ++i)
+ (*data)[i] = static_cast<uint8_t>(kNumDataElements - i);
+
+ const size_t kNumExtraBarsElements = 3;
+ Array<Bar*>* extra_bars = buf.AllocArray<Bar*>(kNumExtraBarsElements);
+ for (size_t i = 0; i < kNumExtraBarsElements; ++i) {
+ Bar* bar = buf.Alloc<Bar>();
+ bar->set_alpha(i * 100);
+ bar->set_beta(i * 100 + 20);
+ bar->set_gamma(i * 100 + 40);
+ (*extra_bars)[i] = bar;
+ }
+
+ Foo* foo = buf.Alloc<Foo>();
+ foo->set_x(1);
+ foo->set_y(2);
+ foo->set_a(false);
+ foo->set_b(true);
+ foo->set_c(false);
+ foo->set_bar(bar);
+ foo->set_data(data);
+ foo->set_extra_bars(extra_bars);
+
+ blah->Frobinate(foo, true);
+
+ return 0;
+}
« no previous file with comments | « mojo/mojo.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698