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

Side by Side 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, 2 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « mojo/mojo.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 // HYPOTHETICAL IDL:
3
4 struct Bar {
5 alpha @0 :uint8;
6 beta @1 :uint8;
7 gamma @2 :uint8;
8 };
9
10 struct Foo {
11 x @0 :int32;
12 y @1 :int32;
13 a @2 :bool;
14 b @3 :bool;
15 c @4 :bool;
16 bar @5 :Bar;
17 extra_bars @7 :array(Bar) [optional];
18 data @6 :array(uint8);
19 };
20
21 interface Blah {
22 Frobinate @0 (foo @0 :Foo, baz @1 :bool);
23 };
24
25 */
26
27 #include <assert.h>
28 #include <stddef.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <new>
35 #include <vector>
36
37 // This would be part of some header file we'd provide.
38
39 typedef uint32_t Handle;
40
41 struct Message {
42 uint32_t name;
43 uint8_t* data_start;
44 uint8_t* data_end;
45 Handle* handles_start;
46 Handle* handles_end;
47 };
48
49 struct MessageHeader {
50 uint32_t num_bytes;
51 uint32_t name;
52 };
53
54 struct StructHeader {
55 uint32_t num_bytes;
56 uint32_t num_fields;
57 };
58
59 struct ArrayHeader {
60 uint32_t num_bytes;
61 uint32_t num_elements;
62 };
63
64 template <typename T> class Array;
65
66 template <typename T>
67 union StructPointer {
68 uint64_t offset;
69 T* ptr;
70 };
71
72 template <typename T>
73 union ArrayPointer {
74 uint64_t offset;
75 Array<T>* ptr;
76 };
77
78 inline void EncodePointer(void* address, uint64_t* offset) {
79 if (!address) {
80 *offset = 0;
81 return;
82 }
83 uint8_t* p_obj = reinterpret_cast<uint8_t*>(address);
84 uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset);
85 assert(p_obj > p_slot);
86 *offset = p_obj - p_slot;
87 }
88
89 template <typename T>
90 inline void DecodePointer(uint64_t* offset, T** ptr) {
91 if (!*offset) {
92 *ptr = NULL;
93 return;
94 }
95 uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset);
96 *ptr = reinterpret_cast<T*>(p_slot + *offset);
piman 2013/09/25 17:26:25 Note: strict aliasing rules only allow reinterpret
97 }
98
99 template <typename T>
100 struct ArrayTraits {
101 typedef T ElementType;
102
103 static T& ToElementRef(ElementType& e) { return e; }
104 static T const& ToElementConstRef(const ElementType& e) { return e; }
105
106 template <typename Allocator>
107 static void CloneElements(Allocator* allocator,
108 ArrayHeader* header,
109 ElementType* elements) {
110 }
111
112 static void EncodePointersAndHandles(ArrayHeader* header,
113 ElementType* elements,
114 std::vector<Handle>* handles) {
115 }
116 static bool DecodePointersAndHandles(ArrayHeader* header,
117 ElementType* elements,
118 const Message& message) {
119 return true;
120 }
121 };
122
123 template <typename P>
124 struct ArrayTraits<P*> {
125 typedef StructPointer<P> ElementType;
126
127 static P*& ToElementRef(ElementType& e) { return e.ptr; }
128 static P* const& ToElementConstRef(const ElementType& e) { return e.ptr; }
129
130 template <typename Allocator>
131 static void CloneElements(Allocator* allocator,
132 ArrayHeader* header,
133 ElementType* elements) {
134 for (uint32_t i = 0; i < header->num_elements; ++i) {
135 if (elements[i].ptr)
136 elements[i].ptr = elements[i].ptr->Clone(allocator);
137 }
138 }
139
140 static void EncodePointersAndHandles(ArrayHeader* header,
141 ElementType* elements,
142 std::vector<Handle>* handles) {
143 for (uint32_t i = 0; i < header->num_elements; ++i) {
144 if (elements[i].ptr)
145 elements[i].ptr->EncodePointersAndHandles(handles);
146 EncodePointer(elements[i].ptr, &elements[i].offset);
147 }
148 }
149 static bool DecodePointersAndHandles(ArrayHeader* header,
150 ElementType* elements,
151 const Message& message) {
152 for (uint32_t i = 0; i < header->num_elements; ++i) {
153 DecodePointer(&elements[i].offset, &elements[i].ptr);
154 if (elements[i].ptr)
155 elements[i].ptr->DecodePointersAndHandles(message);
156 }
157 return true;
158 }
159 };
160
161 template <typename T>
162 class Array {
163 public:
164 explicit Array(size_t num_elements) {
165 // TODO: bools should get packed to a single bit?
166 header_.num_bytes =
167 sizeof(typename ArrayTraits<T>::ElementType) * num_elements +
168 sizeof(ArrayHeader);
169 header_.num_elements = num_elements;
170 }
171
172 template <typename Allocator>
173 Array<T>* Clone(Allocator* allocator) const {
174 Array<T>* array =
175 reinterpret_cast<Array<T>*>(allocator->AllocBytes(header_.num_bytes));
176 memcpy(array, this, header_.num_bytes);
177
178 ArrayTraits<T>::CloneElements(allocator, &array->header_, array->elements_);
179 return array;
180 }
181
182 void EncodePointersAndHandles(std::vector<Handle>* handles) {
183 ArrayTraits<T>::EncodePointersAndHandles(&header_, elements_, handles);
184 }
185 bool DecodePointersAndHandles(const Message& message) {
186 return ArrayTraits<T>::DecodePointersAndHandles(&header_, elements_,
187 message);
188 }
189
190 size_t size() const { return header_.num_elements; }
191
192 T& at(size_t offset) {
193 return ArrayTraits<T>::ToElementRef(elements_[offset]);
194 }
195
196 const T& at(size_t offset) const {
197 return ArrayTraits<T>::ToElementConstRef(elements_[offset]);
198 }
199
200 T& operator[](size_t offset) {
201 return ArrayTraits<T>::ToElementRef(elements_[offset]);
202 }
203
204 const T& operator[](size_t offset) const {
205 return ArrayTraits<T>::ToElementConstRef(elements_[offset]);
206 }
207
208 private:
209 ArrayHeader header_;
210 typename ArrayTraits<T>::ElementType elements_[1]; // Extra elements follow.
211 };
212
213 // The following is a cheezy arena allocator.
214 class Buffer {
215 public:
216 Buffer() : ptr_(NULL), size_(0) {
217 }
218 ~Buffer() { free(ptr_); }
219
220 const uint8_t* data() const { return ptr_; }
221 uint8_t* data() { return ptr_; }
222
223 size_t size() const { return size_; }
224
225 uint8_t* AllocBytes(size_t size) {
226 return Grow(size);
227 }
228
229 template <typename T>
230 T* Alloc() {
231 size_t size = sizeof(T);
232 return new (Grow(size)) T();
233 }
234
235 template <typename T>
236 Array<T>* AllocArray(size_t count) {
237 // (count - 1) because Array<T> has reserved space for the first element.
238 size_t size = sizeof(Array<T>) + sizeof(T) * (count - 1);
239 return new (Grow(size)) Array<T>(count);
240 }
241
242 private:
243 uint8_t* Grow(size_t delta) {
244 // TODO: Align allocations
245 size_t old_size = size_;
246 size_t new_size = old_size + delta;
247 ptr_ = static_cast<uint8_t*>(realloc(ptr_, old_size + delta));
248 size_ = new_size;
249 uint8_t* result = ptr_ + old_size;
250 memset(result, 0, delta);
251 return result;
252 }
253
254 uint8_t* ptr_;
255 size_t size_;
256
257 // NOT IMPLEMENTED
258 Buffer(const Buffer&);
259 void operator=(const Buffer&);
260 };
261
262 //----
263 // Begin generated code.
264
265 // What follows is class definitions corresponding to the structures indicated
266 // by the IDL.
267
268 class Bar {
269 public:
270 Bar() {
271 header_.num_bytes = sizeof(*this) + sizeof(StructHeader);
272 header_.num_fields = 3;
273 }
274
275 Bar* Clone(Buffer* buf) const {
276 Bar* bar = buf->Alloc<Bar>();
277 memcpy(bar, this, sizeof(*this));
278 return bar;
279 }
280
281 void EncodePointersAndHandles(std::vector<Handle>* handles) {
282 }
283 bool DecodePointersAndHandles(const Message& message) {
284 return true;
285 }
286
287 void set_alpha(uint8_t alpha) { d_.alpha = alpha; }
288 void set_beta(uint8_t beta) { d_.beta = beta; }
289 void set_gamma(uint8_t gamma) { d_.gamma = gamma; }
290
291 uint8_t alpha() const { return d_.alpha; }
292 uint8_t beta() const { return d_.beta; }
293 uint8_t gamma() const { return d_.gamma; }
294
295 private:
296 StructHeader header_;
Hajime Morrita 2013/09/25 20:03:55 One possible alternative is to keep the message cl
297 struct {
298 uint8_t alpha;
299 uint8_t beta;
300 uint8_t gamma;
301 } d_;
302
303 ~Bar(); // NOT IMPLEMENTED
304 };
305
306 class Foo {
307 public:
308 Foo() {
309 header_.num_bytes = sizeof(*this) + sizeof(StructHeader);
310 header_.num_fields = 8;
311 }
312
313 Foo* Clone(Buffer* buf) const {
314 Foo* foo = buf->Alloc<Foo>();
315 memcpy(foo, this, sizeof(*this));
316
317 foo->set_bar(foo->bar()->Clone(buf));
318 foo->set_data(foo->data()->Clone(buf));
319 foo->set_extra_bars(foo->extra_bars()->Clone(buf));
320
321 return foo;
322 }
323
324 void EncodePointersAndHandles(std::vector<Handle>* handles) {
325 if (d_.bar.ptr)
326 d_.bar.ptr->EncodePointersAndHandles(handles);
327 EncodePointer(d_.bar.ptr, &d_.bar.offset);
328
329 if (d_.data.ptr)
330 d_.data.ptr->EncodePointersAndHandles(handles);
331 EncodePointer(d_.data.ptr, &d_.data.offset);
332
333 if (d_.extra_bars.ptr)
334 d_.extra_bars.ptr->EncodePointersAndHandles(handles);
335 EncodePointer(d_.extra_bars.ptr, &d_.extra_bars.offset);
336 }
337
338 bool DecodePointersAndHandles(const Message& message) {
339 DecodePointer(&d_.bar.offset, &d_.bar.ptr);
340 if (d_.bar.ptr) {
341 if (!d_.bar.ptr->DecodePointersAndHandles(message))
342 return false;
343 }
344
345 DecodePointer(&d_.data.offset, &d_.data.ptr);
346 if (d_.data.ptr) {
347 if (!d_.data.ptr->DecodePointersAndHandles(message))
348 return false;
349 }
350
351 if (header_.num_fields >= 8) {
352 DecodePointer(&d_.extra_bars.offset, &d_.extra_bars.ptr);
353 if (d_.extra_bars.ptr) {
354 if (!d_.extra_bars.ptr->DecodePointersAndHandles(message))
355 return false;
356 }
357 }
358
359 // TODO: validate
360 return true;
361 }
362
363 void set_x(int32_t x) { d_.x = x; }
364 void set_y(int32_t y) { d_.y = y; }
365 void set_a(bool a) { d_.a = a; }
366 void set_b(bool b) { d_.b = b; }
367 void set_c(bool c) { d_.c = c; }
368 void set_bar(Bar* bar) { d_.bar.ptr = bar; }
369 void set_data(Array<uint8_t>* data) { d_.data.ptr = data; }
370 void set_extra_bars(Array<Bar*>* extra_bars) {
371 d_.extra_bars.ptr = extra_bars;
372 }
373
374 int32_t x() const { return d_.x; }
375 int32_t y() const { return d_.y; }
376 bool a() const { return d_.a; }
377 bool b() const { return d_.b; }
378 bool c() const { return d_.c; }
379 const Bar* bar() const { return d_.bar.ptr; }
380 const Array<uint8_t>* data() const { return d_.data.ptr; }
381 const Array<Bar*>* extra_bars() const {
382 // NOTE: extra_bars is an optional field!
383 return header_.num_fields >= 8 ? d_.extra_bars.ptr : NULL;
384 }
385
386 private:
387 StructHeader header_;
388 struct {
389 int32_t x;
390 int32_t y;
391 uint32_t a : 1;
392 uint32_t b : 1;
393 uint32_t c : 1;
394 StructPointer<Bar> bar;
395 ArrayPointer<uint8_t> data;
396 ArrayPointer<Bar*> extra_bars;
397 } d_;
398
399 ~Foo(); // NOT IMPLEMENTED
400 };
401
402 class Frobinate_Params {
403 public:
404 Frobinate_Params() {
405 header_.num_bytes = sizeof(*this) + sizeof(StructHeader);
406 header_.num_fields = 2;
407 }
408
409 void EncodePointersAndHandles(std::vector<Handle>* handles) {
410 if (d_.foo.ptr)
411 d_.foo.ptr->EncodePointersAndHandles(handles);
412 EncodePointer(d_.foo.ptr, &d_.foo.offset);
413 }
414 bool DecodePointersAndHandles(const Message& message) {
415 DecodePointer(&d_.foo.offset, &d_.foo.ptr);
416 if (d_.foo.ptr) {
417 if (!d_.foo.ptr->DecodePointersAndHandles(message))
418 return false;
419 }
420 // TODO: validate
421 return true;
422 }
423
424 void set_foo(Foo* foo) { d_.foo.ptr = foo; }
425 void set_baz(bool baz) { d_.baz = baz; }
426
427 const Foo* foo() const { return d_.foo.ptr; }
428 bool baz() const { return d_.baz; }
429
430 private:
431 StructHeader header_;
432 struct {
433 StructPointer<Foo> foo;
434 uint32_t baz : 1;
435 } d_;
436
437 ~Frobinate_Params(); // NOT IMPLEMENTED
438 };
439
440 const uint32_t kMessageID_Frobinate = 1;
441
442 //----
443 // The following code would also be generated by our bindings system.
444
445 class Blah {
446 public:
447 virtual void Frobinate(const Foo* foo, bool baz) = 0;
448 };
449
450 class BlahStub : public Blah {
451 public:
452 bool OnMessageReceived(const Message& message) {
453 switch (message.name) {
454 case kMessageID_Frobinate: {
455 Frobinate_Params* params =
456 reinterpret_cast<Frobinate_Params*>(message.data_start);
457 if (!params->DecodePointersAndHandles(message))
458 return false;
459 Frobinate(params->foo(), params->baz());
460 break;
461 }
462 }
463 return true;
464 }
465 };
466
467 class BlahProxy : public Blah {
468 public:
469 virtual void SendMessage(const Message& message) = 0;
470
471 virtual void Frobinate(const Foo* foo, bool baz) {
472 Buffer buf;
473
474 // TODO: We should allocate the MessageHeader here to reserve space.
475 //MessageHeader* header = buf.Alloc<MessageHeader>();
476
477 // We now go about allocating the anonymous Frobinate_Params struct. It
478 // holds the parameters to the Frobinate message.
479 //
480 // Notice how foo is cloned. This causes a copy of foo to be generated
481 // within the same buffer as the Frobinate_Params struct. That's what we
482 // need in order to generate a continguous blob of message data.
483
484 Frobinate_Params* params = buf.Alloc<Frobinate_Params>();
485 params->set_foo(foo->Clone(&buf));
486 params->set_baz(baz);
487
488 // NOTE: If foo happened to be a graph with cycles, then Clone would not
489 // have returned.
490
491 // Last step before sending the message is to encode pointers and handles
492 // so that messages become hermetic. Pointers become offsets and handles
493 // becomes indices into the handles array.
494
495 std::vector<Handle> handles;
496 params->EncodePointersAndHandles(&handles);
497
498 Message message;
499 message.name = kMessageID_Frobinate;
500 message.data_start = buf.data();
501 message.data_end = buf.data() + buf.size();
502 message.handles_start = &handles[0];
503 message.handles_end = &handles[0] + handles.size();
504
505 SendMessage(message);
506 }
507 };
508
509 //----
510 // User code goes here:
511
512 static void PrintSpacer(int depth) {
513 for (int i = 0; i < depth; ++i)
514 printf(" ");
515 }
516
517 static void Print(int depth, const char* name, bool value) {
518 PrintSpacer(depth);
519 printf("%s: %s\n", name, value ? "true" : "false");
520 }
521
522 static void Print(int depth, const char* name, int32_t value) {
523 PrintSpacer(depth);
524 printf("%s: %d\n", name, value);
525 }
526
527 static void Print(int depth, const char* name, uint8_t value) {
528 PrintSpacer(depth);
529 printf("%s: %u\n", name, value);
530 }
531
532 template <typename T>
533 static void Print(int depth, const char* name, const Array<T>* array) {
534 PrintSpacer(depth);
535 printf("%s: %p\n", name, array);
536 if (array) {
537 ++depth;
538 for (size_t i = 0; i < array->size(); ++i) {
539 char buf[32];
540 sprintf(buf, "%lu", i);
541 Print(depth, buf, array->at(i));
542 }
543 --depth;
544 }
545 }
546
547 static void Print(int depth, const char* name, const Bar* bar) {
548 PrintSpacer(depth);
549 printf("%s: %p\n", name, bar);
550 if (bar) {
551 ++depth;
552 Print(depth, "alpha", bar->alpha());
553 Print(depth, "beta", bar->beta());
554 Print(depth, "gamma", bar->gamma());
555 --depth;
556 }
557 }
558
559 static void Print(int depth, const char* name, const Foo* foo) {
560 PrintSpacer(depth);
561 printf("%s: %p\n", name, foo);
562 if (foo) {
563 ++depth;
564 Print(depth, "x", foo->x());
565 Print(depth, "y", foo->y());
566 Print(depth, "a", foo->a());
567 Print(depth, "b", foo->b());
568 Print(depth, "c", foo->c());
569 Print(depth, "bar", foo->bar());
570 Print(depth, "data", foo->data());
571 Print(depth, "extra_bars", foo->extra_bars());
572 --depth;
573 }
574 }
575
576 class BlahImpl : public BlahStub {
577 public:
578 virtual void Frobinate(const Foo* foo, bool baz) {
579 // Users code goes here to handle the incoming Frobinate message.
580 // We'll just dump the Foo structure and all of its members.
581
582 printf("Frobinate:\n");
583
584 int depth = 1;
585 Print(depth, "foo", foo);
586 Print(depth, "baz", baz);
587 }
588 };
589
590 //----
591
592 class BlahProxyImpl : public BlahProxy {
593 public:
594 virtual void SendMessage(const Message& message) {
595 // Imagine some IPC happened here.
596
597 // In the receiving process, an implementation of BlahStub is known to the
598 // system. It receives the incoming message.
599 BlahImpl impl;
600 BlahStub* stub = &impl;
601
602 stub->OnMessageReceived(message);
603 }
604 };
605
606 int main() {
607 // User has a proxy to a Blah somehow.
608 Blah* blah = new BlahProxyImpl();
609
610 // User constructs a message to send.
611
612 // Notice that it doesn't matter in what order the structs / arrays are
613 // allocated. Here, the various members of Foo are allocated before Foo is
614 // allocated.
615
616 Buffer buf;
617
618 Bar* bar = buf.Alloc<Bar>();
619 bar->set_alpha(20);
620 bar->set_beta(40);
621 bar->set_gamma(60);
622
623 const size_t kNumDataElements = 10;
624 Array<uint8_t>* data = buf.AllocArray<uint8_t>(kNumDataElements);
625 for (size_t i = 0; i < kNumDataElements; ++i)
626 (*data)[i] = static_cast<uint8_t>(kNumDataElements - i);
627
628 const size_t kNumExtraBarsElements = 3;
629 Array<Bar*>* extra_bars = buf.AllocArray<Bar*>(kNumExtraBarsElements);
630 for (size_t i = 0; i < kNumExtraBarsElements; ++i) {
631 Bar* bar = buf.Alloc<Bar>();
632 bar->set_alpha(i * 100);
633 bar->set_beta(i * 100 + 20);
634 bar->set_gamma(i * 100 + 40);
635 (*extra_bars)[i] = bar;
636 }
637
638 Foo* foo = buf.Alloc<Foo>();
639 foo->set_x(1);
640 foo->set_y(2);
641 foo->set_a(false);
642 foo->set_b(true);
643 foo->set_c(false);
644 foo->set_bar(bar);
645 foo->set_data(data);
646 foo->set_extra_bars(extra_bars);
647
648 blah->Frobinate(foo, true);
649
650 return 0;
651 }
OLDNEW
« 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