Internal templatization of lazy-loaders

This commit is contained in:
Behdad Esfahbod 2018-08-02 00:38:46 -07:00
parent ed7b2e58fc
commit bdd3c11a19
1 changed files with 32 additions and 42 deletions

View File

@ -590,38 +590,54 @@ struct BEInt<Type, 4>
* Lazy struct and blob loaders. * Lazy struct and blob loaders.
*/ */
/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t. template <typename Subclass,
* I mean, yeah, only every method is different. */ typename Returned,
template <typename T> typename Stored = Returned>
struct hb_lazy_loader_t struct hb_base_lazy_loader_t
{ {
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
inline const Subclass* thiz (void) const { return static_cast<const Subclass *> (this); }
inline void init (hb_face_t *face_) inline void init (hb_face_t *face_)
{ {
face = face_; face = face_;
instance = nullptr; instance = nullptr;
} }
inline const Returned * operator-> (void) const
{
return thiz ()->get ();
}
protected:
hb_face_t *face;
mutable Stored *instance;
};
template <typename T>
struct hb_lazy_loader_t : hb_base_lazy_loader_t<hb_lazy_loader_t<T>, T>
{
inline void fini (void) inline void fini (void)
{ {
if (instance && instance != &Null(T)) if (this->instance && this->instance != &Null(T))
{ {
instance->fini(); this->instance->fini();
free (instance); free (this->instance);
} }
} }
inline const T* get (void) const inline const T* get (void) const
{ {
retry: retry:
T *p = (T *) hb_atomic_ptr_get (&instance); T *p = (T *) hb_atomic_ptr_get (&this->instance);
if (unlikely (!p)) if (unlikely (!p))
{ {
p = (T *) calloc (1, sizeof (T)); p = (T *) calloc (1, sizeof (T));
if (unlikely (!p)) if (unlikely (!p))
p = const_cast<T *> (&Null(T)); p = const_cast<T *> (&Null(T));
else else
p->init (face); p->init (this->face);
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p))) if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&this->instance), nullptr, p)))
{ {
if (p != &Null(T)) if (p != &Null(T))
p->fini (); p->fini ();
@ -630,46 +646,29 @@ struct hb_lazy_loader_t
} }
return p; return p;
} }
inline const T* operator-> (void) const
{
return get ();
}
private:
hb_face_t *face;
mutable T *instance;
}; };
/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t.
* I mean, yeah, only every method is different. */
template <typename T> template <typename T>
struct hb_table_lazy_loader_t struct hb_table_lazy_loader_t : hb_base_lazy_loader_t<hb_table_lazy_loader_t<T>, T, hb_blob_t>
{ {
inline void init (hb_face_t *face_)
{
face = face_;
blob = nullptr;
}
inline void fini (void) inline void fini (void)
{ {
hb_blob_destroy (blob); hb_blob_destroy (this->instance);
} }
inline hb_blob_t* get_blob (void) const inline hb_blob_t* get_blob (void) const
{ {
retry: retry:
hb_blob_t *b = (hb_blob_t *) hb_atomic_ptr_get (&blob); hb_blob_t *b = (hb_blob_t *) hb_atomic_ptr_get (&this->instance);
if (unlikely (!b)) if (unlikely (!b))
{ {
b = hb_sanitize_context_t ().reference_table<T> (face); b = hb_sanitize_context_t ().reference_table<T> (this->face);
if (!hb_atomic_ptr_cmpexch (&blob, nullptr, b)) if (!hb_atomic_ptr_cmpexch (&this->instance, nullptr, b))
{ {
hb_blob_destroy (b); hb_blob_destroy (b);
goto retry; goto retry;
} }
blob = b; this->instance = b;
} }
return b; return b;
} }
@ -679,15 +678,6 @@ struct hb_table_lazy_loader_t
hb_blob_t *b = get_blob (); hb_blob_t *b = get_blob ();
return b->as<T> (); return b->as<T> ();
} }
inline const T* operator-> (void) const
{
return get();
}
private:
hb_face_t *face;
mutable hb_blob_t *blob;
}; };