From 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 15 Feb 2013 16:27:18 -0800 Subject: Sync with 8 months of Google-internal development. Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink). --- README | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'README') diff --git a/README b/README index 45e9ff0..e52f06a 100644 --- a/README +++ b/README @@ -34,6 +34,89 @@ the major things that are broken or not yet implemented yet: - serialization isn't written yet (only deserialization) +C/C++ API +========= + +upb's main interfaces are defined in .h files (like upb/def.h). These header +files are coded in such a way that they are not only compatible with C and C++ +but provide idiomatic interfaces to both (functions for C, classes for C++). + +Here is the general strategy/pattern for this. I'll explain it piece by piece. + +// This defines a type called upb::Foo in C++ or upb_foo in C. In both cases +// there is a typedef for upb_foo, which is important since this is how the +// C functions are defined (which are exposed to both C and C++). + +#ifdef __cplusplus +namespace upb { class Foo; } +typedef upb::Foo upb_foo; +extern "C" { +#else +struct upb_foo; +typedef struct upb_foo upb_foo; +#endif + +// Here is the actual definition of the class/struct. In C++ we get a class +// called upb::Foo and in C we get a struct called "struct upb_foo", but both +// have the same members and the C++ version is "standard-layout" according +// to C++11. This means that the two should be compatible. +// +// In addition to being completely accessible from C, it also provides C++ +// niceities like methods (instead of bare functions). We also get +// encapsulation in C++, even though this is impossible to provide in C. We +// provide all method documentation in the C++ class, since the class/method +// syntax is nicer to read than the bare functions of C. + +#ifdef __cplusplus + +class upb::Foo { + public: + // Method documentation for DoBar(). + void DoBar(int32_t x); + + // Method documentation for IsSpicy(). + bool IsSpicy(); + + private: + +#else +struct upb_foo { +#endif + int32_t private_member; +}; + +// Next follows the C API, which is how the functionality is actually +// implemented. We omit documentation here because everything was documented +// in the C++ class, and it's easy to match the functions 1:1 to the C++ +// methods. +void upb_foo_dobar(upb_foo *f, int32_t x); +bool upb_foo_isspicy(upb_foo *f); + +// Finally we include inline definitions of the C++ methods, which are nothing +// but this wrappers around the C functions. Since these are inline, the C++ +// API imposes no overhead. + +#ifdef __cplusplus +} // extern "C" + +namespace upb { +inline void Foo::DoBar(int32_t x) { upb_foo_dobar(this, x); } +inline bool Foo::IsSpicy() { return upb_foo_isspicy(this); } +} +#endif + +This scheme works pretty nicely. It adds a bit of noise to the header file, but +gives nice, zero-overhead APIs to both C and C++ without having to duplicate +the API documentation. + +The biggest bummer is that there isn't any good way to use C++ inheritance +even for types which are trying to express inheritance in C. C++ just doesn't +give any guarantees about how it will arrange data members in base classes, +so we can't use C++ inheritance while interoperating with C layouts. The +biggest effect of this is that we can't get C++'s nice implicit upcasts; all +upcasts have to be explicit, which is a pain. + + CONTACT ======= -- cgit v1.2.3