Chromium Code Reviews| 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 |