summaryrefslogtreecommitdiff
path: root/upb/refcounted.h
diff options
context:
space:
mode:
authorJosh Haberman <jhaberman@gmail.com>2015-05-18 10:55:20 -0700
committerJosh Haberman <jhaberman@gmail.com>2015-06-02 15:55:45 -0700
commit919fea438a5ac5366684cfa26d2bb3d17519cb60 (patch)
tree6a2d282c3c7910263241e03f41be23c6a6cda710 /upb/refcounted.h
parent6650b3c6527c17965adf7239850857a10d56ba62 (diff)
Ported upb to C89, for greater portability.
A large part of this change contains surface-level porting, like moving variable declarations to the top of the block. However there are a few more substantial things too: - moved internal-only struct definitions to a separate file (structdefs.int.h), for greater encapsulation and ABI compatibility. - removed the UPB_UPCAST macro, since it requires access to the internal-only struct definitions. Replaced uses with calls to inline, type-safe casting functions. - removed the UPB_DEFINE_CLASS/UPB_DEFINE_STRUCT macros. Class and struct definitions are now more explicit -- you get to see the actual class/struct keywords in the source. The casting convenience functions have been moved into UPB_DECLARE_DERIVED_TYPE() and UPB_DECLARE_DERIVED_TYPE2(). - the new way that we duplicate base methods in derived types is also more convenient and requires less duplication. It is also less greppable, but hopefully that is not too big a problem. Compiler flags (-std=c89 -pedantic) should help to rigorously enforce that the code is free of C99-isms. A few functions are not available in C89 (strtoll). There are temporary, hacky solutions in place.
Diffstat (limited to 'upb/refcounted.h')
-rw-r--r--upb/refcounted.h206
1 files changed, 125 insertions, 81 deletions
diff --git a/upb/refcounted.h b/upb/refcounted.h
index fe77077..4013906 100644
--- a/upb/refcounted.h
+++ b/upb/refcounted.h
@@ -21,84 +21,102 @@
#include "upb/table.int.h"
-// Reference tracking will check ref()/unref() operations to make sure the
-// ref ownership is correct. Where possible it will also make tools like
-// Valgrind attribute ref leaks to the code that took the leaked ref, not
-// the code that originally created the object.
-//
-// Enabling this requires the application to define upb_lock()/upb_unlock()
-// functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE).
-// For this reason we don't enable it by default, even in debug builds.
+/* Reference tracking will check ref()/unref() operations to make sure the
+ * ref ownership is correct. Where possible it will also make tools like
+ * Valgrind attribute ref leaks to the code that took the leaked ref, not
+ * the code that originally created the object.
+ *
+ * Enabling this requires the application to define upb_lock()/upb_unlock()
+ * functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE).
+ * For this reason we don't enable it by default, even in debug builds.
+ */
-// #define UPB_DEBUG_REFS
+/* #define UPB_DEBUG_REFS */
#ifdef __cplusplus
namespace upb { class RefCounted; }
#endif
-UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted);
+UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted)
struct upb_refcounted_vtbl;
-UPB_DEFINE_CLASS0(upb::RefCounted,
+#ifdef __cplusplus
+
+class upb::RefCounted {
public:
- // Returns true if the given object is frozen.
+ /* Returns true if the given object is frozen. */
bool IsFrozen() const;
- // Increases the ref count, the new ref is owned by "owner" which must not
- // already own a ref (and should not itself be a refcounted object if the ref
- // could possibly be circular; see below).
- // Thread-safe iff "this" is frozen.
+ /* Increases the ref count, the new ref is owned by "owner" which must not
+ * already own a ref (and should not itself be a refcounted object if the ref
+ * could possibly be circular; see below).
+ * Thread-safe iff "this" is frozen. */
void Ref(const void *owner) const;
- // Release a ref that was acquired from upb_refcounted_ref() and collects any
- // objects it can.
+ /* Release a ref that was acquired from upb_refcounted_ref() and collects any
+ * objects it can. */
void Unref(const void *owner) const;
- // Moves an existing ref from "from" to "to", without changing the overall
- // ref count. DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
- // but "to" may not be NULL.
+ /* Moves an existing ref from "from" to "to", without changing the overall
+ * ref count. DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
+ * but "to" may not be NULL. */
void DonateRef(const void *from, const void *to) const;
- // Verifies that a ref to the given object is currently held by the given
- // owner. Only effective in UPB_DEBUG_REFS builds.
+ /* Verifies that a ref to the given object is currently held by the given
+ * owner. Only effective in UPB_DEBUG_REFS builds. */
void CheckRef(const void *owner) const;
private:
- UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted);
-,
-UPB_DEFINE_STRUCT0(upb_refcounted,
- // A single reference count shared by all objects in the group.
+ UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted)
+#else
+struct upb_refcounted {
+#endif
+ /* TODO(haberman): move the actual structure definition to structdefs.int.h.
+ * The only reason they are here is because inline functions need to see the
+ * definition of upb_handlers, which needs to see this definition. But we
+ * can change the upb_handlers inline functions to deal in raw offsets
+ * instead.
+ */
+
+ /* A single reference count shared by all objects in the group. */
uint32_t *group;
- // A singly-linked list of all objects in the group.
+ /* A singly-linked list of all objects in the group. */
upb_refcounted *next;
- // Table of function pointers for this type.
+ /* Table of function pointers for this type. */
const struct upb_refcounted_vtbl *vtbl;
- // Maintained only when mutable, this tracks the number of refs (but not
- // ref2's) to this object. *group should be the sum of all individual_count
- // in the group.
+ /* Maintained only when mutable, this tracks the number of refs (but not
+ * ref2's) to this object. *group should be the sum of all individual_count
+ * in the group. */
uint32_t individual_count;
bool is_frozen;
#ifdef UPB_DEBUG_REFS
- upb_inttable *refs; // Maps owner -> trackedref for incoming refs.
- upb_inttable *ref2s; // Set of targets for outgoing ref2s.
+ upb_inttable *refs; /* Maps owner -> trackedref for incoming refs. */
+ upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */
+#endif
+};
+
+#ifdef UPB_DEBUG_REFS
+#define UPB_REFCOUNT_INIT(refs, ref2s) \
+ {&static_refcount, NULL, NULL, 0, true, refs, ref2s}
+#else
+#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true}
#endif
-));
-UPB_BEGIN_EXTERN_C // {
+UPB_BEGIN_EXTERN_C
-// It is better to use tracked refs when possible, for the extra debugging
-// capability. But if this is not possible (because you don't have easy access
-// to a stable pointer value that is associated with the ref), you can pass
-// UPB_UNTRACKED_REF instead.
+/* It is better to use tracked refs when possible, for the extra debugging
+ * capability. But if this is not possible (because you don't have easy access
+ * to a stable pointer value that is associated with the ref), you can pass
+ * UPB_UNTRACKED_REF instead. */
extern const void *UPB_UNTRACKED_REF;
-// Native C API.
+/* Native C API. */
bool upb_refcounted_isfrozen(const upb_refcounted *r);
void upb_refcounted_ref(const upb_refcounted *r, const void *owner);
void upb_refcounted_unref(const upb_refcounted *r, const void *owner);
@@ -106,37 +124,70 @@ void upb_refcounted_donateref(
const upb_refcounted *r, const void *from, const void *to);
void upb_refcounted_checkref(const upb_refcounted *r, const void *owner);
-
-// Internal-to-upb Interface ///////////////////////////////////////////////////
+#define UPB_REFCOUNTED_CMETHODS(type, upcastfunc) \
+ UPB_INLINE bool type ## _isfrozen(const type *v) { \
+ return upb_refcounted_isfrozen(upcastfunc(v)); \
+ } \
+ UPB_INLINE void type ## _ref(const type *v, const void *owner) { \
+ upb_refcounted_ref(upcastfunc(v), owner); \
+ } \
+ UPB_INLINE void type ## _unref(const type *v, const void *owner) { \
+ upb_refcounted_unref(upcastfunc(v), owner); \
+ } \
+ UPB_INLINE void type ## _donateref(const type *v, const void *from, const void *to) { \
+ upb_refcounted_donateref(upcastfunc(v), from, to); \
+ } \
+ UPB_INLINE void type ## _checkref(const type *v, const void *owner) { \
+ upb_refcounted_checkref(upcastfunc(v), owner); \
+ }
+
+#define UPB_REFCOUNTED_CPPMETHODS \
+ bool IsFrozen() const { \
+ return upb::upcast_to<const upb::RefCounted>(this)->IsFrozen(); \
+ } \
+ void Ref(const void *owner) const { \
+ return upb::upcast_to<const upb::RefCounted>(this)->Ref(owner); \
+ } \
+ void Unref(const void *owner) const { \
+ return upb::upcast_to<const upb::RefCounted>(this)->Unref(owner); \
+ } \
+ void DonateRef(const void *from, const void *to) const { \
+ return upb::upcast_to<const upb::RefCounted>(this)->DonateRef(from, to); \
+ } \
+ void CheckRef(const void *owner) const { \
+ return upb::upcast_to<const upb::RefCounted>(this)->CheckRef(owner); \
+ }
+
+/* Internal-to-upb Interface **************************************************/
typedef void upb_refcounted_visit(const upb_refcounted *r,
const upb_refcounted *subobj,
void *closure);
struct upb_refcounted_vtbl {
- // Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
- // Must be longjmp()-safe.
+ /* Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
+ * Must be longjmp()-safe. */
void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c);
- // Must free the object and release all references to other objects.
+ /* Must free the object and release all references to other objects. */
void (*free)(upb_refcounted *r);
};
-// Initializes the refcounted with a single ref for the given owner. Returns
-// false if memory could not be allocated.
+/* Initializes the refcounted with a single ref for the given owner. Returns
+ * false if memory could not be allocated. */
bool upb_refcounted_init(upb_refcounted *r,
const struct upb_refcounted_vtbl *vtbl,
const void *owner);
-// Adds a ref from one refcounted object to another ("from" must not already
-// own a ref). These refs may be circular; cycles will be collected correctly
-// (if conservatively). These refs do not need to be freed in from's free()
-// function.
+/* Adds a ref from one refcounted object to another ("from" must not already
+ * own a ref). These refs may be circular; cycles will be collected correctly
+ * (if conservatively). These refs do not need to be freed in from's free()
+ * function. */
void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from);
-// Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
-// object it can. This is only necessary when "from" no longer points to "r",
-// and not from from's "free" function.
+/* Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
+ * object it can. This is only necessary when "from" no longer points to "r",
+ * and not from from's "free" function. */
void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from);
#define upb_ref2(r, from) \
@@ -144,37 +195,30 @@ void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from);
#define upb_unref2(r, from) \
upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from)
-// Freezes all mutable object reachable by ref2() refs from the given roots.
-// This will split refcounting groups into precise SCC groups, so that
-// refcounting of frozen objects can be more aggressive. If memory allocation
-// fails, or if more than 2**31 mutable objects are reachable from "roots", or
-// if the maximum depth of the graph exceeds "maxdepth", false is returned and
-// the objects are unchanged.
-//
-// After this operation succeeds, the objects are frozen/const, and may not be
-// used through non-const pointers. In particular, they may not be passed as
-// the second parameter of upb_refcounted_{ref,unref}2(). On the upside, all
-// operations on frozen refcounteds are threadsafe, and objects will be freed
-// at the precise moment that they become unreachable.
-//
-// Caller must own refs on each object in the "roots" list.
+/* Freezes all mutable object reachable by ref2() refs from the given roots.
+ * This will split refcounting groups into precise SCC groups, so that
+ * refcounting of frozen objects can be more aggressive. If memory allocation
+ * fails, or if more than 2**31 mutable objects are reachable from "roots", or
+ * if the maximum depth of the graph exceeds "maxdepth", false is returned and
+ * the objects are unchanged.
+ *
+ * After this operation succeeds, the objects are frozen/const, and may not be
+ * used through non-const pointers. In particular, they may not be passed as
+ * the second parameter of upb_refcounted_{ref,unref}2(). On the upside, all
+ * operations on frozen refcounteds are threadsafe, and objects will be freed
+ * at the precise moment that they become unreachable.
+ *
+ * Caller must own refs on each object in the "roots" list. */
bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
int maxdepth);
-// Shared by all compiled-in refcounted objects.
+/* Shared by all compiled-in refcounted objects. */
extern uint32_t static_refcount;
-UPB_END_EXTERN_C // }
-
-#ifdef UPB_DEBUG_REFS
-#define UPB_REFCOUNT_INIT(refs, ref2s) \
- {&static_refcount, NULL, NULL, 0, true, refs, ref2s}
-#else
-#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true}
-#endif
+UPB_END_EXTERN_C
#ifdef __cplusplus
-// C++ Wrappers.
+/* C++ Wrappers. */
namespace upb {
inline bool RefCounted::IsFrozen() const {
return upb_refcounted_isfrozen(this);
@@ -191,7 +235,7 @@ inline void RefCounted::DonateRef(const void *from, const void *to) const {
inline void RefCounted::CheckRef(const void *owner) const {
upb_refcounted_checkref(this, owner);
}
-} // namespace upb
+} /* namespace upb */
#endif
-#endif // UPB_REFCOUNT_H_
+#endif /* UPB_REFCOUNT_H_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback