lilypond-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Almost, but not quite: C++ STL in LilyPond


From: David Kastrup
Subject: Re: Almost, but not quite: C++ STL in LilyPond
Date: Wed, 06 May 2020 00:03:50 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

David Kastrup <address@hidden> writes:

> Dan Eble <address@hidden> writes:
>
>> On May 5, 2020, at 13:37, David Kastrup <address@hidden> wrote:
>>> 
>>> What I have ready-to-use is something that stores like an SCM value but
>>> behaves like a Smob pointer with regard to -> and * usage.
>>
>> Oh.  I believe I have some of that too.  Excerpt:
>>
>> // specialization for pointers
>> template <class T>
>> class ly_scm_t<T *>
>> {
>> private:
>>   using traits = ly_scm_traits<T *>;
>>
>> private:
>>   SCM scm_ = SCM_UNDEFINED;
>>
>> public:
>>   ly_scm_t () = default;
>>   ly_scm_t (const ly_scm_t &) = default;
>>   ly_scm_t &operator = (const ly_scm_t &) = default;
>>   ~ly_scm_t () = default;
>>
>>   explicit ly_scm_t (T *v) : scm_ (traits::to_scm (v)) {}
>>
>>   explicit operator bool () const { return traits::has_value (scm_); }
>>   operator T *() const { return traits::to_value (scm_); }
>>   T *operator ->() { return operator T * (); }
>>   // TODO: operator *
>> };
>
> Well, mine is a lot less formal I guess.  Something akin to
>
> template <class T>
> class Scm_ptr
> {
>   SCM scm_;
> public:
>   Scm_ptr () : scm_ (SCM_UNDEFINED) {}
>   Scm_ptr (SCM v) : scm_ (v)
>   {
>     assert (SCM_UNBNDP (v) || T::is_smob (v));
>   }
>   Scm_ptr (const T *p) : scm_ (p ? p->self_scm () : SCM_UNDEFINED) {}
>   Scm_ptr & operator = (T* p)
>   {
>     scm_ = p ? p->self_scm () : SCM_UNDEFINED;
>     return *this;
>   }
>   Scm_ptr & operator = (SCM s)
>   {
>     if (SCM_UNBNDP (s) || LY_ASSERT_SMOB (T, s, 1))
>       scm_ = s;
>     else
>       scm_ = SCM_UNDEFINED;
>     return *this;
>   }
>   T * operator -> () const
>   {
>     return dynamic_cast<T *> (T::unchecked_unsmob (scm_));
>   }
>   operator T * () const
>   {
>     return dynamic_cast<T *> (T::unchecked_unsmob (scm_));
>   }
>   operator SCM () const
>   {
>     return scm_;
>   }
>   operator bool () const
>   {
>     return SCM_BNDP (scm_);
>   }
> };
>
> One thing here is that being under control of a wrapper, one can use
> unchecked unsmobs.  I am not sure about conversion to SCM: this uses a
> conversion operator.  I was tempted to use operator & instead.  I did
> not have any traits in mind yet, but formalising the allocation/garbage
> protection thing would certainly call for something identifiable with
> regard to types that LilyPond knows how to allocate/protect.

To expound somewhat: a vector class (replete with iterators etc)
implemented through SCM would internally consist of one SCM cell holding
a Scheme vector and one size_t number for its current length.  The
capacity would be the actual size of the Scheme vector (with extra slots
filled with SCM_UNBNDP).  So the garbage collector footprint is
basically "pouo" (look up Scheme struct vtables for the meaning).  A
Smob allocator basically collects the strings of its constituents at
their respective offsets when it is first called and initializes a
Scheme vtable with it, and then uses this vtable to allocate the smob as
an SCM value.  Simple_smob can create a "smobbed copy" on demand in a
similar way.

If everything can be represented/mapped in similar manner, the Scheme
garbage collector does not need any interaction with user-written code
for doing its job.

And I really think that's where we want to go in order to get memory
semantics and behavior that are "Guile orthodox" to a degree that we'll
get more attention for problems we are experiencing than what we have
been working with so far.

-- 
David Kastrup



reply via email to

[Prev in Thread] Current Thread [Next in Thread]