OLD | NEW |
---|---|
(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 <stddef.h> | |
28 #include <stdint.h> | |
29 #include <stdio.h> | |
30 #include <stdlib.h> | |
31 #include <string.h> | |
32 #include <vector> | |
33 | |
34 // This would be part of some header file we'd provide. | |
35 | |
36 typedef uint32_t Handle; | |
37 | |
38 struct Message { | |
39 uint32_t name; | |
40 uint8_t* data_start; | |
41 uint8_t* data_end; | |
42 Handle* handles_start; | |
43 Handle* handles_end; | |
44 }; | |
45 | |
46 struct StructHeader { | |
47 uint32_t num_bytes; | |
48 uint32_t num_fields; | |
49 }; | |
50 | |
51 struct ArrayHeader { | |
52 uint32_t num_bytes; | |
53 uint32_t num_elements; | |
54 }; | |
55 | |
56 template <typename T> class Array; | |
57 | |
58 template <typename T> | |
59 union StructPointer { | |
60 uint64_t offset; | |
61 T* ptr; | |
62 }; | |
63 | |
64 template <typename T> | |
65 union ArrayPointer { | |
66 uint64_t offset; | |
67 Array<T>* ptr; | |
68 }; | |
69 | |
70 inline void EncodePointer(void* address, uint64_t* offset) { | |
71 if (!address) { | |
72 *offset = 0; | |
73 return; | |
74 } | |
75 uint8_t* p_obj = reinterpret_cast<uint8_t*>(address); | |
76 uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset); | |
77 *offset = p_obj - p_slot; | |
yzshen1
2013/09/24 18:32:56
Is it intended to use an unsigned number for |offs
| |
78 } | |
79 | |
80 template <typename T> | |
81 inline void DecodePointer(uint64_t* offset, T** ptr) { | |
82 if (!*offset) { | |
83 *ptr = NULL; | |
84 return; | |
85 } | |
86 uint8_t* p_slot = reinterpret_cast<uint8_t*>(offset); | |
87 *ptr = reinterpret_cast<T*>(p_slot + *offset); | |
88 } | |
89 | |
90 template <typename T> | |
91 struct ArrayTraits { | |
92 typedef T ElementType; | |
93 | |
94 static T& ToElementRef(ElementType& e) { return e; } | |
95 static T const& ToElementConstRef(const ElementType& e) { return e; } | |
96 | |
97 static void EncodePointersAndHandles(ArrayHeader* header, | |
98 ElementType* elements, | |
99 std::vector<Handle>* handles) { | |
100 } | |
101 static bool DecodePointersAndHandles(ArrayHeader* header, | |
102 ElementType* elements, | |
103 const Message& message) { | |
104 return true; | |
105 } | |
106 }; | |
107 | |
108 template <typename P> | |
109 struct ArrayTraits<P*> { | |
110 typedef StructPointer<P> ElementType; | |
111 | |
112 static P*& ToElementRef(ElementType& e) { return e.ptr; } | |
113 static P* const& ToElementConstRef(const ElementType& e) { return e.ptr; } | |
114 | |
115 static void EncodePointersAndHandles(ArrayHeader* header, | |
116 ElementType* elements, | |
117 std::vector<Handle>* handles) { | |
118 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
119 if (elements[i].ptr) | |
120 elements[i].ptr->EncodePointersAndHandles(handles); | |
121 EncodePointer(elements[i].ptr, &elements[i].offset); | |
122 } | |
123 } | |
124 static bool DecodePointersAndHandles(ArrayHeader* header, | |
125 ElementType* elements, | |
126 const Message& message) { | |
127 for (uint32_t i = 0; i < header->num_elements; ++i) { | |
128 DecodePointer(&elements[i].offset, &elements[i].ptr); | |
129 if (elements[i].ptr) | |
130 elements[i].ptr->DecodePointersAndHandles(message); | |
131 } | |
132 return true; | |
133 } | |
134 }; | |
135 | |
136 template <typename T> | |
137 class Array { | |
138 public: | |
139 void Initialize(size_t num_elements) { | |
140 // TODO: bools should get packed to a single bit? | |
141 header_.num_bytes = | |
142 sizeof(typename ArrayTraits<T>::ElementType) * num_elements - | |
143 sizeof(ArrayHeader); | |
144 header_.num_elements = num_elements; | |
145 } | |
146 | |
147 void EncodePointersAndHandles(std::vector<Handle>* handles) { | |
148 ArrayTraits<T>::EncodePointersAndHandles(&header_, elements_, handles); | |
149 } | |
150 bool DecodePointersAndHandles(const Message& message) { | |
151 return ArrayTraits<T>::DecodePointersAndHandles(&header_, elements_, | |
152 message); | |
153 } | |
154 | |
155 size_t size() const { return header_.num_elements; } | |
156 | |
157 T& at(size_t offset) { | |
158 return ArrayTraits<T>::ToElementRef(elements_[offset]); | |
159 } | |
160 | |
161 const T& at(size_t offset) const { | |
162 return ArrayTraits<T>::ToElementConstRef(elements_[offset]); | |
163 } | |
164 | |
165 T& operator[](size_t offset) { | |
166 return ArrayTraits<T>::ToElementRef(elements_[offset]); | |
167 } | |
168 | |
169 const T& operator[](size_t offset) const { | |
170 return ArrayTraits<T>::ToElementConstRef(elements_[offset]); | |
171 } | |
172 | |
173 private: | |
174 ArrayHeader header_; | |
175 typename ArrayTraits<T>::ElementType elements_[1]; | |
176 }; | |
177 | |
178 //---- | |
179 // Begin generated code. | |
180 | |
181 // What follows is class definitions corresponding to the structures indicated | |
182 // by the IDL. | |
183 | |
184 class Bar { | |
185 public: | |
186 void Initialize() { | |
187 header_.num_bytes = sizeof(*this) - sizeof(StructHeader); | |
188 header_.num_fields = 3; | |
189 } | |
190 | |
191 void EncodePointersAndHandles(std::vector<Handle>* handles) { | |
192 } | |
193 bool DecodePointersAndHandles(const Message& message) { | |
194 return true; | |
195 } | |
196 | |
197 void set_alpha(uint8_t alpha) { d_.alpha = alpha; } | |
198 void set_beta(uint8_t beta) { d_.beta = beta; } | |
199 void set_gamma(uint8_t gamma) { d_.gamma = gamma; } | |
200 | |
201 uint8_t alpha() const { return d_.alpha; } | |
202 uint8_t beta() const { return d_.beta; } | |
203 uint8_t gamma() const { return d_.gamma; } | |
204 | |
205 private: | |
206 StructHeader header_; | |
207 struct { | |
208 uint8_t alpha; | |
209 uint8_t beta; | |
210 uint8_t gamma; | |
211 } d_; | |
212 | |
213 // NOT IMPLEMENTED | |
214 Bar(); | |
215 ~Bar(); | |
216 }; | |
217 | |
218 class Foo { | |
219 public: | |
220 void Initialize() { | |
221 header_.num_bytes = sizeof(*this) - sizeof(StructHeader); | |
222 header_.num_fields = 8; | |
223 } | |
224 | |
225 void EncodePointersAndHandles(std::vector<Handle>* handles) { | |
226 if (d_.bar.ptr) | |
227 d_.bar.ptr->EncodePointersAndHandles(handles); | |
228 EncodePointer(d_.bar.ptr, &d_.bar.offset); | |
229 | |
230 if (d_.data.ptr) | |
231 d_.data.ptr->EncodePointersAndHandles(handles); | |
232 EncodePointer(d_.data.ptr, &d_.data.offset); | |
233 | |
234 if (d_.extra_bars.ptr) | |
235 d_.extra_bars.ptr->EncodePointersAndHandles(handles); | |
236 EncodePointer(d_.extra_bars.ptr, &d_.extra_bars.offset); | |
237 } | |
238 | |
239 bool DecodePointersAndHandles(const Message& message) { | |
240 DecodePointer(&d_.bar.offset, &d_.bar.ptr); | |
241 if (d_.bar.ptr) { | |
242 if (!d_.bar.ptr->DecodePointersAndHandles(message)) | |
243 return false; | |
244 } | |
245 | |
246 DecodePointer(&d_.data.offset, &d_.data.ptr); | |
247 if (d_.data.ptr) { | |
248 if (!d_.data.ptr->DecodePointersAndHandles(message)) | |
249 return false; | |
250 } | |
251 | |
252 if (header_.num_fields >= 8) { | |
253 DecodePointer(&d_.extra_bars.offset, &d_.extra_bars.ptr); | |
254 if (d_.extra_bars.ptr) { | |
255 if (!d_.extra_bars.ptr->DecodePointersAndHandles(message)) | |
256 return false; | |
257 } | |
258 } | |
259 | |
260 // TODO: validate | |
261 return true; | |
262 } | |
263 | |
264 void set_x(int32_t x) { d_.x = x; } | |
265 void set_y(int32_t y) { d_.y = y; } | |
266 void set_a(bool a) { d_.a = a; } | |
267 void set_b(bool b) { d_.b = b; } | |
268 void set_c(bool c) { d_.c = c; } | |
269 void set_bar(Bar* bar) { d_.bar.ptr = bar; } | |
270 void set_data(Array<uint8_t>* data) { d_.data.ptr = data; } | |
271 void set_extra_bars(Array<Bar*>* extra_bars) { | |
272 d_.extra_bars.ptr = extra_bars; | |
273 } | |
274 | |
275 int32_t x() const { return d_.x; } | |
276 int32_t y() const { return d_.y; } | |
277 bool a() const { return d_.a; } | |
278 bool b() const { return d_.b; } | |
279 bool c() const { return d_.c; } | |
280 const Bar* bar() const { return d_.bar.ptr; } | |
281 const Array<uint8_t>* data() const { return d_.data.ptr; } | |
282 const Array<Bar*>* extra_bars() const { | |
283 // NOTE: extra_bars is an optional field! | |
284 return header_.num_fields >= 8 ? d_.extra_bars.ptr : NULL; | |
285 } | |
286 | |
287 private: | |
288 StructHeader header_; | |
289 struct { | |
290 int32_t x; | |
291 int32_t y; | |
292 uint32_t a : 1; | |
293 uint32_t b : 1; | |
294 uint32_t c : 1; | |
295 StructPointer<Bar> bar; | |
296 ArrayPointer<uint8_t> data; | |
297 ArrayPointer<Bar*> extra_bars; | |
298 } d_; | |
299 | |
300 // NOT IMPLEMENTED | |
301 Foo(); | |
302 ~Foo(); | |
303 }; | |
304 | |
305 class Frobinate_Params { | |
306 public: | |
307 void Initialize() { | |
308 header_.num_bytes = sizeof(*this) - sizeof(StructHeader); | |
309 header_.num_fields = 2; | |
310 } | |
311 | |
312 void EncodePointersAndHandles(std::vector<Handle>* handles) { | |
313 if (d_.foo.ptr) | |
314 d_.foo.ptr->EncodePointersAndHandles(handles); | |
315 EncodePointer(d_.foo.ptr, &d_.foo.offset); | |
316 } | |
317 bool DecodePointersAndHandles(const Message& message) { | |
318 DecodePointer(&d_.foo.offset, &d_.foo.ptr); | |
319 if (d_.foo.ptr) { | |
320 if (!d_.foo.ptr->DecodePointersAndHandles(message)) | |
321 return false; | |
322 } | |
323 // TODO: validate | |
324 return true; | |
325 } | |
326 | |
327 void set_foo(Foo* foo) { d_.foo.ptr = foo; } | |
328 void set_baz(bool baz) { d_.baz = baz; } | |
329 | |
330 const Foo* foo() const { return d_.foo.ptr; } | |
331 bool baz() const { return d_.baz; } | |
332 | |
333 private: | |
334 StructHeader header_; | |
335 struct { | |
336 StructPointer<Foo> foo; | |
337 uint32_t baz : 1; | |
338 } d_; | |
339 | |
340 // NOT IMPLEMENTED | |
341 Frobinate_Params(); | |
342 ~Frobinate_Params(); | |
343 }; | |
344 | |
345 const uint32_t kMessageID_Frobinate = 1; | |
346 | |
347 //---- | |
348 // The following code would also be generated by our bindings system. | |
349 | |
350 class Blah { | |
351 public: | |
352 virtual void Frobinate(const Foo* foo, bool baz) = 0; | |
353 }; | |
354 | |
355 class BlahStub : public Blah { | |
356 public: | |
357 bool OnMessageReceived(const Message& message) { | |
358 switch (message.name) { | |
359 case kMessageID_Frobinate: { | |
360 Frobinate_Params* params = | |
361 reinterpret_cast<Frobinate_Params*>(message.data_start); | |
362 if (!params->DecodePointersAndHandles(message)) | |
363 return false; | |
364 Frobinate(params->foo(), params->baz()); | |
365 break; | |
366 } | |
367 } | |
368 return true; | |
369 } | |
370 }; | |
371 | |
372 #if 0 | |
373 // TODO: Figure out how to make the client-side work nicely. | |
374 class BlahProxy : public Blah { | |
375 public: | |
376 virtual void SendMessage(const Message& message) = 0; | |
377 | |
378 virtual void Frobinate(const Foo* foo, bool baz) { | |
379 } | |
380 | |
381 virtual void Frobinate(const Frobinate_Params* params) { | |
382 } | |
383 }; | |
384 #endif | |
385 | |
386 //---- | |
387 // User code goes here: | |
388 | |
389 static void PrintSpacer(int depth) { | |
390 for (int i = 0; i < depth; ++i) | |
391 printf(" "); | |
392 } | |
393 | |
394 static void Print(int depth, const char* name, bool value) { | |
395 PrintSpacer(depth); | |
396 printf("%s: %s\n", name, value ? "true" : "false"); | |
397 } | |
398 | |
399 static void Print(int depth, const char* name, int32_t value) { | |
400 PrintSpacer(depth); | |
401 printf("%s: %d\n", name, value); | |
402 } | |
403 | |
404 static void Print(int depth, const char* name, uint8_t value) { | |
405 PrintSpacer(depth); | |
406 printf("%s: %u\n", name, value); | |
407 } | |
408 | |
409 template <typename T> | |
410 static void Print(int depth, const char* name, const Array<T>* array) { | |
411 PrintSpacer(depth); | |
412 printf("%s: %p\n", name, array); | |
413 if (array) { | |
414 ++depth; | |
415 for (size_t i = 0; i < array->size(); ++i) { | |
416 char buf[32]; | |
417 sprintf(buf, "%lu", i); | |
418 Print(depth, buf, array->at(i)); | |
419 } | |
420 --depth; | |
421 } | |
422 } | |
423 | |
424 static void Print(int depth, const char* name, const Bar* bar) { | |
425 PrintSpacer(depth); | |
426 printf("%s: %p\n", name, bar); | |
427 if (bar) { | |
428 ++depth; | |
429 Print(depth, "alpha", bar->alpha()); | |
430 Print(depth, "beta", bar->beta()); | |
431 Print(depth, "gamma", bar->gamma()); | |
432 --depth; | |
433 } | |
434 } | |
435 | |
436 static void Print(int depth, const char* name, const Foo* foo) { | |
437 PrintSpacer(depth); | |
438 printf("%s: %p\n", name, foo); | |
439 if (foo) { | |
440 ++depth; | |
441 Print(depth, "x", foo->x()); | |
442 Print(depth, "y", foo->y()); | |
443 Print(depth, "a", foo->a()); | |
444 Print(depth, "b", foo->b()); | |
445 Print(depth, "c", foo->c()); | |
446 Print(depth, "bar", foo->bar()); | |
447 Print(depth, "data", foo->data()); | |
448 Print(depth, "extra_bars", foo->extra_bars()); | |
449 --depth; | |
450 } | |
451 } | |
452 | |
453 class BlahImpl : public BlahStub { | |
454 public: | |
455 virtual void Frobinate(const Foo* foo, bool baz) { | |
456 // Users code goes here to handle the incoming Frobinate message. | |
457 // We'll just dump the Foo structure and all of its members. | |
458 | |
459 printf("Frobinate:\n"); | |
460 | |
461 int depth = 1; | |
462 Print(depth, "foo", foo); | |
463 Print(depth, "baz", baz); | |
464 } | |
465 }; | |
466 | |
467 //---- | |
468 | |
469 // The following is just some cheezy buffer allocation code. | |
470 // We'd want to sugar this somehow. | |
471 | |
472 class Buffer { | |
473 public: | |
474 Buffer() : ptr_(NULL), size_(0) { | |
475 } | |
476 ~Buffer() { free(ptr_); } | |
477 | |
478 const uint8_t* data() const { return ptr_; } | |
479 uint8_t* data() { return ptr_; } | |
480 | |
481 size_t size() const { return size_; } | |
482 | |
483 template <typename T> | |
484 T* Alloc() { | |
485 T* ptr = reinterpret_cast<T*>(Grow(sizeof(T))); | |
486 ptr->Initialize(); | |
487 return ptr; | |
488 } | |
489 | |
490 template <typename T> | |
491 Array<T>* AllocArray(size_t count) { | |
492 Array<T>* ptr = reinterpret_cast<Array<T>*>( | |
493 Grow(sizeof(Array<T>) + sizeof(T) * (count - 1))); | |
494 ptr->Initialize(count); | |
495 return ptr; | |
496 } | |
497 | |
498 private: | |
499 uint8_t* Grow(size_t delta) { | |
500 size_t old_size = size_; | |
501 size_t new_size = old_size + delta; | |
502 ptr_ = static_cast<uint8_t*>(realloc(ptr_, old_size + delta)); | |
503 size_ = new_size; | |
504 uint8_t* result = ptr_ + old_size; | |
505 memset(result, 0, delta); | |
506 return result; | |
507 } | |
508 | |
509 uint8_t* ptr_; | |
510 size_t size_; | |
511 | |
512 // NOT IMPLEMENTED | |
513 Buffer(const Buffer&); | |
514 void operator=(const Buffer&); | |
515 }; | |
516 | |
517 int main() { | |
518 // User constructs a message to send. TODO: Add more sugar to this! | |
519 | |
520 Buffer buf; | |
521 | |
522 Frobinate_Params* params = buf.Alloc<Frobinate_Params>(); | |
523 params->set_baz(true); | |
524 | |
525 Foo* foo = buf.Alloc<Foo>(); | |
526 foo->set_x(1); | |
527 foo->set_y(2); | |
528 foo->set_a(false); | |
529 foo->set_b(true); | |
530 foo->set_c(false); | |
531 | |
532 Bar* bar = buf.Alloc<Bar>(); | |
533 bar->set_alpha(20); | |
534 bar->set_beta(40); | |
535 bar->set_gamma(60); | |
536 foo->set_bar(bar); | |
537 | |
538 const size_t kNumDataElements = 10; | |
539 Array<uint8_t>* data = buf.AllocArray<uint8_t>(kNumDataElements); | |
540 for (size_t i = 0; i < kNumDataElements; ++i) | |
541 data->at(i) = static_cast<uint8_t>(kNumDataElements - i); | |
542 foo->set_data(data); | |
543 | |
544 const size_t kNumExtraBarsElements = 3; | |
545 Array<Bar*>* extra_bars = buf.AllocArray<Bar*>(kNumExtraBarsElements); | |
546 for (size_t i = 0; i < kNumExtraBarsElements; ++i) { | |
547 Bar* bar = buf.Alloc<Bar>(); | |
548 bar->set_alpha(i * 100); | |
549 bar->set_beta(i * 100 + 20); | |
550 bar->set_gamma(i * 100 + 40); | |
551 extra_bars->at(i) = bar; | |
552 } | |
553 foo->set_extra_bars(extra_bars); | |
554 | |
555 params->set_foo(foo); | |
556 | |
557 // Last step before sending the message is to encode pointers and handles so | |
558 // that messages become hermetic. Pointers become offsets and handles becomes | |
559 // indices into the handles array. | |
560 | |
561 std::vector<Handle> handles; | |
562 params->EncodePointersAndHandles(&handles); | |
563 | |
564 Message message; | |
565 message.name = kMessageID_Frobinate; | |
566 message.data_start = buf.data(); | |
567 message.data_end = buf.data() + buf.size(); | |
568 message.handles_start = &handles[0]; | |
569 message.handles_end = &handles[0] + handles.size(); | |
570 | |
571 // At this point, the user would normally call WriteMessage to write buf | |
572 // to a pipe. Here, we are leaving that part out. We'll just forward buf | |
573 // as a simulated incoming message to the generated bindings for handling | |
574 // a message. OnMessageReceived would ordinarily be prefixed with a call | |
575 // to ReadMessage to read an incoming message from a pipe. | |
576 | |
577 BlahStub* stub = new BlahImpl(); | |
578 stub->OnMessageReceived(message); | |
579 return 0; | |
580 } | |
OLD | NEW |