[lazy] More shuffle

This commit is contained in:
Behdad Esfahbod 2018-08-12 12:40:24 -07:00
parent 5d9863be6e
commit 5abdf5eeba
1 changed files with 35 additions and 47 deletions

View File

@ -599,24 +599,22 @@ struct hb_lazy_loader_t
{ {
static_assert (WheresData > 0, ""); static_assert (WheresData > 0, "");
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
inline const Subclass* thiz (void) const { return static_cast<const Subclass *> (this); }
inline Subclass* thiz (void) { return static_cast<Subclass *> (this); }
inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */ inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
inline void init (void) inline void init (void) { instance.set_relaxed (nullptr); }
inline void fini (void) { destroy (instance.get ()); }
static inline void destroy (Stored *p)
{ {
instance.set_relaxed (nullptr); if (p && p != Subclass::get_null ())
} Subclass::destroy (p);
inline void fini (void)
{
Stored *p = this->instance.get ();
if (p)
thiz ()->destroy (p);
} }
inline const Returned * operator -> (void) const { return thiz ()->get (); } inline const Returned * operator -> (void) const { return get (); }
inline const Returned & operator * (void) const { return *thiz ()->get (); } inline const Returned & operator * (void) const { return *get (); }
inline Data * get_data (void) const
{
return *(((Data **) this) - WheresData);
}
inline Stored * get_stored (void) const inline Stored * get_stored (void) const
{ {
@ -624,15 +622,15 @@ struct hb_lazy_loader_t
Stored *p = this->instance.get (); Stored *p = this->instance.get ();
if (unlikely (!p)) if (unlikely (!p))
{ {
Data *data= *(((Data **) this) - WheresData); Data *data = get_data ();
if (likely (!p)) if (likely (data))
p = thiz ()->create (data); p = Subclass::create (data);
if (unlikely (!p)) if (unlikely (!p))
p = thiz ()->create (nullptr); /* Produce nil object. */ p = const_cast<Stored *> (Subclass::get_null ());
assert (p); assert (p);
if (unlikely (!this->instance.cmpexch (nullptr, p))) if (unlikely (!this->instance.cmpexch (nullptr, p)))
{ {
thiz ()->destroy (p); destroy (p);
goto retry; goto retry;
} }
} }
@ -645,23 +643,16 @@ struct hb_lazy_loader_t
* However, to make TSan, etc, happy, we using cmpexch. */ * However, to make TSan, etc, happy, we using cmpexch. */
retry: retry:
Stored *p = this->instance.get (); Stored *p = this->instance.get ();
if (p) if (unlikely (!this->instance.cmpexch (p, instance_)))
{ goto retry;
if (unlikely (!this->instance.cmpexch (p, instance_))) destroy (p);
goto retry;
thiz ()->destroy (p);
}
} }
inline const Returned * get (void) const inline const Returned * get (void) const { return Subclass::convert (get_stored ()); }
{
return thiz ()->convert (get_stored ());
}
static inline const Returned* convert (const Stored *p) /* To be possibly overloaded by subclasses. */
{ static inline const Returned* convert (const Stored *p) { return p; }
return p; static inline const Stored* get_null (void) { return &Null(Stored); }
}
private: private:
/* Must only have one pointer. */ /* Must only have one pointer. */
@ -677,22 +668,19 @@ struct hb_object_lazy_loader_t : hb_lazy_loader_t<hb_object_lazy_loader_t<Wheres
{ {
static inline T *create (hb_face_t *face) static inline T *create (hb_face_t *face)
{ {
if (unlikely (!face))
return const_cast<T *> (&Null(T));
T *p = (T *) calloc (1, sizeof (T)); T *p = (T *) calloc (1, sizeof (T));
if (unlikely (!p)) if (likely (p))
p = const_cast<T *> (&Null(T));
else
p->init (face); p->init (face);
return p; return p;
} }
static inline void destroy (T *p) static inline void destroy (T *p)
{ {
if (p != &Null(T)) p->fini ();
{ free (p);
p->fini(); }
free (p); static inline const T *get_null (void)
} {
return &Null(T);
} }
}; };
@ -701,18 +689,18 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<hb_table_lazy_loader_t<T, Where
hb_face_t, WheresFace, hb_face_t, WheresFace,
T, hb_blob_t> T, hb_blob_t>
{ {
static_assert (WheresFace > 0, "");
static inline hb_blob_t *create (hb_face_t *face) static inline hb_blob_t *create (hb_face_t *face)
{ {
if (unlikely (!face))
return hb_blob_get_empty ();
return hb_sanitize_context_t ().reference_table<T> (face); return hb_sanitize_context_t ().reference_table<T> (face);
} }
static inline void destroy (hb_blob_t *p) static inline void destroy (hb_blob_t *p)
{ {
hb_blob_destroy (p); hb_blob_destroy (p);
} }
static inline const hb_blob_t *get_null (void)
{
return hb_blob_get_empty ();
}
static inline const T* convert (const hb_blob_t *blob) static inline const T* convert (const hb_blob_t *blob)
{ {
return blob->as<T> (); return blob->as<T> ();