#define SMOBS_HH
#include "lily-guile.hh"
+#include "lily-proto.hh"
#include "warn.hh"
#include <string>
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<T> (SCM x) - unpack X and return a pointer to the C++ object,
+ or 0 if it has the wrong type.
IMPLEMENTATION
debugging purposes. If the class does not define this function,
the output will be #<Classname> 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.
// class) to make sure the variable is actually instantiated.
class Scm_init {
+ static const Scm_init * list_;
+ void (*const fun_)(void);
+ Scm_init const * const next_;
+ Scm_init (); // don't use default constructor, don't define
+ Scm_init (const Scm_init &); // don't define copy constructor
public:
- Scm_init () { }
- Scm_init (void (*fun) (void))
- {
- add_scm_init_func (fun);
- }
+ Scm_init (void (*fun) (void)) : fun_ (fun), next_ (list_)
+ { list_ = this; }
+ static void init ();
};
template <class Super>
static Scm_init scm_init_;
static void init (void);
static string smob_name_;
+protected:
static Super *unchecked_unsmob (SCM s)
{
return reinterpret_cast<Super *> (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.
// 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<Super> 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;
+ // Define type_p_name_ in the Super class as a const char * const.
+ // Without such definition it defaults to 0, producing no predicate.
+
+ 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<PMF>, \
+ 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 <SCM (Super::*pmf)(void)>
+ static SCM smob_trampoline (SCM self)
+ {
+ return (Super::unchecked_unsmob (self)->*pmf)();
+ }
+ template <SCM (Super::*pmf)(SCM)>
+ static SCM smob_trampoline (SCM self, SCM arg1)
+ {
+ return (Super::unchecked_unsmob (self)->*pmf)(arg1);
+ }
+ template <SCM (Super::*pmf)(SCM, SCM)>
+ static SCM smob_trampoline (SCM self, SCM arg1, SCM arg2)
+ {
+ return (Super::unchecked_unsmob (self)->*pmf)(arg1, arg2);
+ }
+ template <SCM (Super::*pmf)(SCM, SCM, SCM)>
+ 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);
{
return is_smob (s) ? SCM_BOOL_T : SCM_BOOL_F;
}
- static Super *unsmob (SCM s)
- {
- return is_smob (s) ? Super::unchecked_unsmob (s) : 0;
- }
+
+ template <class T>
+ friend T *unsmob (SCM s);
+
+ template <class T>
+ friend T *ly_assert_smob (SCM s, int number, const char *fun);
};
+template <class T>
+inline T *unsmob (SCM s)
+{
+ return T::is_smob (s) ? dynamic_cast<T *> (T::unchecked_unsmob (s)) : 0;
+}
+
// Simple smobs
template <class Super>
class Simple_smob : public Smob_base<Super> {
void protect_smob (SCM smob, SCM *prot_cons);
void unprotect_smob (SCM smob, SCM *prot_cons);
+// The Smob_core class is not templated and contains material not
+// depending on the Super class.
+
+class Smob_core {
+protected:
+ SCM self_scm_;
+ Smob_core () : self_scm_ (SCM_UNDEFINED) { };
+public:
+ SCM self_scm () const { return self_scm_; }
+ Listener get_listener (SCM callback);
+};
+
template <class Super>
-class Smob : public Smob_base<Super> {
+class Smob : public Smob_core, public Smob_base<Super> {
private:
- SCM self_scm_;
SCM protection_cons_;
Smob (const Smob<Super> &); // Do not define! Not copyable!
protected:
- Smob () : self_scm_ (SCM_UNDEFINED), protection_cons_ (SCM_EOL) { };
+ Smob () : protection_cons_ (SCM_EOL) { };
public:
static size_t free_smob (SCM obj)
{
}
SCM unprotected_smobify_self ()
{
- self_scm_ = Smob_base<Super>::register_ptr (static_cast<Super *> (this));
- return self_scm_;
+ SCM s = Smob_base<Super>::register_ptr (static_cast<Super *> (this));
+ self_scm_ = s;
+ return s;
}
void protect ()
{
protect_smob (self_scm_, &protection_cons_);
}
+ void smobify_self () {
+ protect_smob (unprotected_smobify_self (), &protection_cons_);
+ }
SCM unprotect ()
{
- unprotect_smob (self_scm_, &protection_cons_);
- return self_scm_;
- }
- void smobify_self () {
- self_scm_ = unprotected_smobify_self ();
- protect ();
+ SCM s = self_scm_;
+ unprotect_smob (s, &protection_cons_);
+ return s;
}
- SCM self_scm () const { return self_scm_; }
};
extern bool parsed_objects_should_be_dead;
// 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; \