Reduce storage by sharing face amongst lazy_loaders

This commit is contained in:
Behdad Esfahbod 2018-08-02 01:27:40 -07:00
parent bdd3c11a19
commit ff7826e90b
4 changed files with 88 additions and 70 deletions

View File

@ -590,93 +590,106 @@ struct BEInt<Type, 4>
* Lazy struct and blob loaders.
*/
template <typename Subclass,
template <unsigned int WheresFace,
typename Subclass,
typename Returned,
typename Stored = Returned>
struct hb_base_lazy_loader_t
{
static_assert (WheresFace > 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 init (hb_face_t *face_)
inline void init (void)
{
face = face_;
instance = nullptr;
}
inline void fini (void)
{
if (instance)
thiz ()->destroy (instance);
}
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)
{
if (this->instance && this->instance != &Null(T))
{
this->instance->fini();
free (this->instance);
}
}
inline const T* get (void) const
inline Stored * get_stored (void) const
{
retry:
T *p = (T *) hb_atomic_ptr_get (&this->instance);
Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance);
if (unlikely (!p))
{
p = (T *) calloc (1, sizeof (T));
if (unlikely (!p))
p = const_cast<T *> (&Null(T));
else
p->init (this->face);
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&this->instance), nullptr, p)))
hb_face_t *face = *(((hb_face_t **) this) - WheresFace);
p = thiz ()->create (face);
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<Stored **>(&this->instance), nullptr, p)))
{
if (p != &Null(T))
p->fini ();
thiz ()->destroy (p);
goto retry;
}
}
return p;
}
inline const Returned * get (void) const
{
return thiz ()->convert (get_stored ());
}
static inline const Returned* convert (const Stored *p)
{
return p;
}
private:
/* Must only have one pointer. */
mutable Stored *instance;
};
template <typename T>
struct hb_table_lazy_loader_t : hb_base_lazy_loader_t<hb_table_lazy_loader_t<T>, T, hb_blob_t>
template <unsigned int WheresFace, typename T>
struct hb_lazy_loader_t : hb_base_lazy_loader_t<WheresFace, hb_lazy_loader_t<WheresFace, T>, T>
{
inline void fini (void)
static inline T *create (hb_face_t *face)
{
hb_blob_destroy (this->instance);
T *p = (T *) calloc (1, sizeof (T));
if (unlikely (!p))
p = const_cast<T *> (&Null(T));
else
p->init (face);
return p;
}
static inline void destroy (T *p)
{
if (p != &Null(T))
{
p->fini();
free (p);
}
}
};
template <unsigned int WheresFace, typename T>
struct hb_table_lazy_loader_t : hb_base_lazy_loader_t<WheresFace, hb_table_lazy_loader_t<WheresFace, T>, T, hb_blob_t>
{
static inline hb_blob_t *create (hb_face_t *face)
{
return hb_sanitize_context_t ().reference_table<T> (face);
}
static inline void destroy (hb_blob_t *p)
{
hb_blob_destroy (p);
}
static inline const T* convert (const hb_blob_t *blob)
{
return blob->as<T> ();
}
inline hb_blob_t* get_blob (void) const
{
retry:
hb_blob_t *b = (hb_blob_t *) hb_atomic_ptr_get (&this->instance);
if (unlikely (!b))
{
b = hb_sanitize_context_t ().reference_table<T> (this->face);
if (!hb_atomic_ptr_cmpexch (&this->instance, nullptr, b))
{
hb_blob_destroy (b);
goto retry;
}
this->instance = b;
}
return b;
}
inline const T* get (void) const
{
hb_blob_t *b = get_blob ();
return b->as<T> ();
return this->get_stored ();
}
};

View File

@ -44,10 +44,12 @@ struct hb_ot_font_t
OT::cmap::accelerator_t cmap;
OT::hmtx::accelerator_t h_metrics;
OT::vmtx::accelerator_t v_metrics;
hb_lazy_loader_t<OT::glyf::accelerator_t> glyf;
hb_lazy_loader_t<OT::CBDT::accelerator_t> cbdt;
hb_lazy_loader_t<OT::post::accelerator_t> post;
hb_lazy_loader_t<OT::kern::accelerator_t> kern;
hb_face_t *face; /* MUST be before the lazy loaders. */
hb_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
hb_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
hb_lazy_loader_t<3, OT::post::accelerator_t> post;
hb_lazy_loader_t<4, OT::kern::accelerator_t> kern;
};
@ -62,10 +64,11 @@ _hb_ot_font_create (hb_face_t *face)
ot_font->cmap.init (face);
ot_font->h_metrics.init (face);
ot_font->v_metrics.init (face, ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
ot_font->glyf.init (face);
ot_font->cbdt.init (face);
ot_font->post.init (face);
ot_font->kern.init (face);
ot_font->face = face;
ot_font->glyf.init ();
ot_font->cbdt.init ();
ot_font->post.init ();
ot_font->kern.init ();
return ot_font;
}

View File

@ -172,11 +172,12 @@ struct hb_ot_layout_t
const struct OT::GPOS *gpos;
/* TODO Move the following out of this struct. */
hb_table_lazy_loader_t<struct OT::BASE> base;
hb_table_lazy_loader_t<struct OT::MATH> math;
hb_table_lazy_loader_t<struct OT::fvar> fvar;
hb_table_lazy_loader_t<struct OT::avar> avar;
hb_table_lazy_loader_t<struct AAT::morx> morx;
hb_face_t *face; /* MUST be before the lazy loaders. */
hb_table_lazy_loader_t<1, struct OT::BASE> base;
hb_table_lazy_loader_t<2, struct OT::MATH> math;
hb_table_lazy_loader_t<3, struct OT::fvar> fvar;
hb_table_lazy_loader_t<4, struct OT::avar> avar;
hb_table_lazy_loader_t<5, struct AAT::morx> morx;
unsigned int gsub_lookup_count;
unsigned int gpos_lookup_count;

View File

@ -63,10 +63,11 @@ _hb_ot_layout_create (hb_face_t *face)
layout->gpos_blob = hb_sanitize_context_t ().reference_table<OT::GPOS> (face);
layout->gpos = layout->gpos_blob->as<OT::GPOS> ();
layout->math.init (face);
layout->fvar.init (face);
layout->avar.init (face);
layout->morx.init (face);
layout->face = face;
layout->math.init ();
layout->fvar.init ();
layout->avar.init ();
layout->morx.init ();
{
/*