X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Finclude%2Fsmobs.hh;h=00217866dc07dc92eff400e23050d50b46f67a3b;hb=e9e5132fe398480220731a3992b40c0f89c018bd;hp=7097bb3d48c6605b4a08ff769d54bc80be9e0651;hpb=a4cc910a3401d25bb94ff0ecb4dc18f681c71004;p=lilypond.git diff --git a/lily/include/smobs.hh b/lily/include/smobs.hh index 7097bb3d48..00217866dc 100644 --- a/lily/include/smobs.hh +++ b/lily/include/smobs.hh @@ -95,14 +95,36 @@ Complex smobs are created by deriving from Smob. + However, this is not sufficient when classes with their own + protectable elements are derived from the Complex base class. This + is because initialization order is a tricky thing: once a base class + calls smobify_self () in its constructor, further allocations during + construction of base class and derived classes might lead to + mark_smob calls on the object under construction. When those call a + virtual function like derived_mark, the virtual function + corresponding to the incompletely initialized object of derived + class type is likely to be called. + + The order of initialization of an object consists in calling the + constructors of virtual base classes, then of non-virtual base + classes, then initializing all data members. + + As a result, the constructor of a derived class comes too late for + initialization of data members that may be accessed in the + derived_mark kind of functions. + + Such data members are consequently moved into Preinit_* classes + which come before the smobifying base class in derivation order and + construct the contained data members in a state suitable for + derived_mark calls. + + 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 @@ -122,7 +144,7 @@ debugging purposes. If the class does not define this function, the output will be # when printing. - - a static const type_p_name_[] string set to something like + - a static const * const type_p_name_ string set to something like "ly:grob?". When provided, an accordingly named function for checking for the given smob type will be available in Scheme. @@ -153,11 +175,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. @@ -179,48 +201,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) { }; + + // Define type_p_name_ in the Super class as a const char * const. + // Without such definition it defaults to 0, producing no predicate. - // 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; + static const char * const type_p_name_; // = 0 // 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); @@ -229,18 +265,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