X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Finclude%2Fsmobs.hh;h=889d86a8cab3a342b374593a7a6afa1879d98f9f;hb=36fba3138858ee42ba3f03e3de0efa1d1f49d147;hp=62eefeb2cec3c3825dd08da36afefcadd324941a;hpb=4088b7570b18704917b0c721b3979e421084ef0a;p=lilypond.git diff --git a/lily/include/smobs.hh b/lily/include/smobs.hh index 62eefeb2ce..889d86a8ca 100644 --- a/lily/include/smobs.hh +++ b/lily/include/smobs.hh @@ -21,6 +21,7 @@ #define SMOBS_HH #include "lily-guile.hh" +#include "lily-proto.hh" #include "warn.hh" #include @@ -96,12 +97,10 @@ CALLING INTERFACE - Common public methods to C++ smob objects: + Common global functions for accessing C++ smob objects: - - unsmob (SCM x) - unpacks X and returns pointer to the C++ object, - or 0 if it has the wrong type. This can be used as a boolean - condition at C++ level. - - smob_p (SCM x) returns #t or #f at Scheme level. + - unsmob (SCM x) - unpack X and return a pointer to the C++ object, + or 0 if it has the wrong type. IMPLEMENTATION @@ -152,11 +151,11 @@ class Smob_base static Scm_init scm_init_; static void init (void); static string smob_name_; +protected: static Super *unchecked_unsmob (SCM s) { return reinterpret_cast (SCM_SMOB_DATA (s)); } -protected: // reference scm_init_ in smob_tag which is sure to be called. The // constructor, in contrast, may not be called at all in classes // like Smob1. @@ -178,48 +177,62 @@ private: // Most default functions are do-nothings. void init() will // recognize their address when not overriden and will then refrain // altogether from passing the the respective callbacks to GUILE. - SCM mark_smob (void); + SCM mark_smob (void) const; static SCM mark_trampoline (SCM); // Used for calling mark_smob static size_t free_smob (SCM obj); static SCM equal_p (SCM, SCM); - int print_smob (SCM, scm_print_state *); + int print_smob (SCM, scm_print_state *) const; static int print_trampoline (SCM, SCM, scm_print_state *); + static void smob_proc_init (scm_t_bits) { }; - // type_p_name_ can be overriden in the Super class with a static - // const char [] string. This requires both a declaration in the - // class as well as a single instantiation outside. Using a - // template specialization for supplying a different string name - // right in Smob_base itself seems tempting, but the C++ - // rules would then require a specialization declaration at the - // class definition site as well as a specialization instantiation - // in a single compilation unit. That requires just as much source - // code maintenance while being harder to understand and quite - // trickier in its failure symptoms when things go wrong. So we - // just use a static zero as "not here" indication. - static const int type_p_name_ = 0; + // type_p_name_ has to be defined in the Super class, either with a + // static const char [] string or as a null pointer of type const + // char *. We used to provide a default here for convenience, but + // battling the various conflicting C++ standards was too much of a + // hassle. // LY_DECLARE_SMOB_PROC is used in the Super class definition for - // making a smob callable like a function. Declaration has to be - // public. It may be either be completed with a semicolon in which - // case a definition of the member function smob_proc has to be done - // outside of the class body, or the semicolon is left off and an - // inline function body is added immediately below. It would be - // nice if this were a non-static member function but it would seem - // tricky to do the required trampolining for unsmobbing the first - // argument of the callback and using it as a this pointer. -#define LY_DECLARE_SMOB_PROC(REQ, OPT, VAR, ARGLIST) \ - static const int smob_proc_signature_ = ((REQ)<<8)|((OPT)<<4)|(VAR); \ - static SCM smob_proc ARGLIST - - // a separate LY_DEFINE_SMOB_PROC seems sort of pointless as it - // would just result in SCM CLASS::smob_proc ARGLIST - // - // The default case without function functionality is recognized by - // smob_proc_signature being -1. - static const int smob_proc = 0; - static const int smob_proc_signature_ = -1; + // making a smob callable like a function. Its first argument is a + // function member pointer constant, to a function taking the + // correct number of SCM arguments and returning SCM. The function + // itself has to be defined separately. + +#define LY_DECLARE_SMOB_PROC(PMF, REQ, OPT, VAR) \ + static void smob_proc_init (scm_t_bits smob_tag) \ + { \ + scm_set_smob_apply (smob_tag, \ + (scm_t_subr)smob_trampoline, \ + REQ, OPT, VAR); \ + } + + // Well, function template argument packs are a C++11 feature. So + // we just define a bunch of trampolines manually. It turns out + // that GUILE 1.8.8 cannot actually make callable structures with + // more than 3 arguments anyway. That's surprising, to say the + // least, but in emergency situations one can always use a "rest" + // argument and take it apart manually. + + template + static SCM smob_trampoline (SCM self) + { + return (Super::unchecked_unsmob (self)->*pmf)(); + } + template + static SCM smob_trampoline (SCM self, SCM arg1) + { + return (Super::unchecked_unsmob (self)->*pmf)(arg1); + } + template + static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2) + { + return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2); + } + template + static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2, SCM arg3) + { + return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2, arg3); + } -public: static bool is_smob (SCM s) { return SCM_SMOB_PREDICATE (smob_tag (), s); @@ -228,18 +241,18 @@ public: { return is_smob (s) ? SCM_BOOL_T : SCM_BOOL_F; } - static Super *unsmob (SCM s) - { - return is_smob (s) ? Super::unchecked_unsmob (s) : 0; - } -}; -// derived_unsmob includes a dynamic_cast: + template + friend T *unsmob (SCM s); + + template + friend T *ly_assert_smob (SCM s, int number, const char *fun); +}; template -inline T *derived_unsmob (SCM arg) +inline T *unsmob (SCM s) { - return dynamic_cast (T::unsmob (arg)); + return T::is_smob (s) ? dynamic_cast (T::unchecked_unsmob (s)) : 0; } // Simple smobs @@ -270,6 +283,7 @@ protected: Smob_core () : self_scm_ (SCM_UNDEFINED) { }; public: SCM self_scm () const { return self_scm_; } + Listener get_listener (SCM callback); }; template @@ -331,7 +345,7 @@ public: // least some, so they are apparently not protected in spite of being // included in the GC scans. So it would appear that scanning smobs // is not equivalent to marking them. Ugh. -#if !defined(NDEBUG) && !GUILEV2 +#if defined(DEBUG) && !GUILEV2 #define ASSERT_LIVE_IS_ALLOWED(arg) \ do { \ static parsed_dead pass_here; \