From 43f2455cbda22c513f2885d760ca2766b23e100f Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 29 Jul 2014 16:12:53 -0700 Subject: [PATCH] Added UPB_UNTRACKED_REF and some more handler overload options. --- tests/test_cpp.cc | 20 ++++++++++++++ tests/test_def.c | 18 +++++++++++++ upb/handlers-inl.h | 66 ++++++++++++++++++++++++++++++++++++++-------- upb/refcounted.c | 9 +++++++ upb/refcounted.h | 6 +++++ 5 files changed, 108 insertions(+), 11 deletions(-) diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc index 370c7b04d3..7ca5a0df1f 100644 --- a/tests/test_cpp.cc +++ b/tests/test_cpp.cc @@ -433,6 +433,25 @@ class StringBufTesterSizeTMethodNoHandlerDataNoHandle } }; +class StringBufTesterBoolMethodNoHandlerDataNoHandle + : public StringBufTesterBase { + public: + typedef StringBufTesterBoolMethodNoHandlerDataNoHandle ME; + void Register(upb::Handlers* h, const upb::FieldDef* f) { + UPB_UNUSED(f); + ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); + handler_data_val_ = kExpectedHandlerData; + } + + private: + bool Handler(const char *buf, size_t len) { + ASSERT(buf == &buf_); + seen_ = true; + len_ = len; + return true; + } +}; + class StartMsgTesterBase { public: // We don't need the FieldDef it will create, but the test harness still @@ -1124,6 +1143,7 @@ int run_tests(int argc, char *argv[]) { TestHandler(); TestHandler(); TestHandler(); + TestHandler(); TestMismatchedTypes(); diff --git a/tests/test_def.c b/tests/test_def.c index 7efd2b09f0..92b461febe 100644 --- a/tests/test_def.c +++ b/tests/test_def.c @@ -25,6 +25,23 @@ static void test_empty_symtab() { upb_symtab_unref(s, &s); } +static void test_noreftracking() { + // Reftracking is not required; clients can pass UPB_UNTRACKED_REF for owner. + upb_msgdef *md = upb_msgdef_new(UPB_UNTRACKED_REF); + upb_msgdef_ref(md, UPB_UNTRACKED_REF); + + // Clients can mix tracked and untracked refs. + upb_msgdef_ref(md, &md); + + upb_msgdef_unref(md, UPB_UNTRACKED_REF); + upb_msgdef_unref(md, UPB_UNTRACKED_REF); + + // Call some random function on the messagedef to test that it is alive. + ASSERT(!upb_msgdef_isfrozen(md)); + + upb_msgdef_unref(md, &md); +} + static upb_symtab *load_test_proto(void *owner) { upb_symtab *s = upb_symtab_new(owner); ASSERT(s); @@ -271,5 +288,6 @@ int run_tests(int argc, char *argv[]) { test_replacement(); test_freeze_free(); test_partial_freeze(); + test_noreftracking(); return 0; } diff --git a/upb/handlers-inl.h b/upb/handlers-inl.h index b4ba4a311f..14ecb410b3 100644 --- a/upb/handlers-inl.h +++ b/upb/handlers-inl.h @@ -586,6 +586,17 @@ void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } +// Function wrapper that munges the return value from bool to void*. +template +void *ReturnClosureOrBreak2(P1 p1, P2 p2) { + return F(p1, p2) ? p1 : UPB_BREAK; +} + +template +void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) { + return F(p1, p2, p3) ? p1 : UPB_BREAK; +} + // For the string callback, which takes five params, returns the size param. template @@ -595,6 +606,15 @@ size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, return p4; } +// For the string callback, which takes five params, returns the size param or +// zero. +template +size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4, + const BufferHandle *p5) { + return F(p1, p2, p3, p4, p5) ? p4 : 0; +} + // If we have a function returning void but want a function returning bool, wrap // it in a function that returns true. template @@ -619,17 +639,6 @@ struct MaybeWrapReturn, void *> { typedef Func3, I> Func; }; -// If our function returns void but we want one returning size_t, wrap it in a -// function that returns the size argument. -template -struct MaybeWrapReturn< - Func5, - size_t> { - typedef Func5, I> Func; -}; - // If our function returns R* but we want one returning void*, wrap it in a // function that casts to void*. template @@ -645,6 +654,41 @@ struct MaybeWrapReturn, void *, Func; }; +// If our function returns bool but we want one returning void*, wrap it in a +// function that returns either the first param or UPB_BREAK. +template +struct MaybeWrapReturn, void *> { + typedef Func2, I> Func; +}; + +template +struct MaybeWrapReturn, void *> { + typedef Func3, I> + Func; +}; + +// If our function returns void but we want one returning size_t, wrap it in a +// function that returns the size argument. +template +struct MaybeWrapReturn< + Func5, + size_t> { + typedef Func5, I> Func; +}; + +// If our function returns bool but we want one returning size_t, wrap it in a +// function that returns either 0 or the buf size. +template +struct MaybeWrapReturn< + Func5, + size_t> { + typedef Func5, I> Func; +}; + // ConvertParams /////////////////////////////////////////////////////////////// // Template class that converts the function parameters if necessary, and diff --git a/upb/refcounted.c b/upb/refcounted.c index 4e01081350..cba535fa25 100644 --- a/upb/refcounted.c +++ b/upb/refcounted.c @@ -25,6 +25,9 @@ static void freeobj(upb_refcounted *o); +const char untracked_val; +const void *UPB_UNTRACKED_REF = &untracked_val; + /* arch-specific atomic primitives *******************************************/ #ifdef UPB_THREAD_UNSAFE ////////////////////////////////////////////////////// @@ -111,6 +114,9 @@ static trackedref *trackedref_new(bool is_ref2) { } static void track(const upb_refcounted *r, const void *owner, bool ref2) { + assert(owner); + if (owner == UPB_UNTRACKED_REF) return; + upb_lock(); upb_value v; if (upb_inttable_lookupptr(r->refs, owner, &v)) { @@ -140,6 +146,9 @@ static void track(const upb_refcounted *r, const void *owner, bool ref2) { } static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { + assert(owner); + if (owner == UPB_UNTRACKED_REF) return; + upb_lock(); upb_value v; bool found = upb_inttable_lookupptr(r->refs, owner, &v); diff --git a/upb/refcounted.h b/upb/refcounted.h index ab56e4d609..42251b1e28 100644 --- a/upb/refcounted.h +++ b/upb/refcounted.h @@ -89,6 +89,12 @@ UPB_DEFINE_STRUCT0(upb_refcounted, 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. +extern const void *UPB_UNTRACKED_REF; + // Native C API. bool upb_refcounted_isfrozen(const upb_refcounted *r); void upb_refcounted_ref(const upb_refcounted *r, const void *owner);