From e0f3cab2466e3d47e16a18270b5026eae1daa807 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 1 Jun 2022 11:51:43 -0600 Subject: [PATCH] [cplusplus] Add hb-cplusplus.hh Fixes https://github.com/harfbuzz/harfbuzz/issues/2152 --- src/Makefile.sources | 1 + src/hb-cplusplus.hh | 133 +++++++++++++++++++++++++++++++++++++ src/meson.build | 1 + src/test-map.cc | 1 - src/test-set.cc | 2 - test/api/test-c.c | 2 +- test/api/test-cplusplus.cc | 84 ++++++++++++++++++++++- 7 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 src/hb-cplusplus.hh diff --git a/src/Makefile.sources b/src/Makefile.sources index 20c5188e2..c2e0fee33 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -224,6 +224,7 @@ HB_BASE_headers = \ hb-blob.h \ hb-buffer.h \ hb-common.h \ + hb-cplusplus.hh \ hb-deprecated.h \ hb-draw.h \ hb-face.h \ diff --git a/src/hb-cplusplus.hh b/src/hb-cplusplus.hh new file mode 100644 index 000000000..122c6920e --- /dev/null +++ b/src/hb-cplusplus.hh @@ -0,0 +1,133 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_CPLUSPLUS_HH +#define HB_CPLUSPLUS_HH + +#include "hb.h" + +HB_BEGIN_DECLS +HB_END_DECLS + +#ifdef __cplusplus + +#include + +#if 0 +#if !(__cplusplus >= 201103L) +#error "HarfBuzz C++ helpers require C++11" +#endif +#endif + +namespace hb { + + +template +struct vtable; + +template +struct shared_ptr +{ + using v = vtable; + + explicit shared_ptr (T *p = nullptr) : p (p) {} + shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {} + shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; } + shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; } + shared_ptr& operator = (shared_ptr &&o) { destroy (); p = o.p; o.p = nullptr; return *this; } + ~shared_ptr () { v::destroy (p); } + + T* get() const { return p; } + + void swap (shared_ptr &o) { std::swap (p, o.p); } + friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); } + + operator T * () const { return p; } + T& operator * () const { return *get (); } + T* operator -> () const { return get (); } + operator bool () { return p; } + bool operator == (const shared_ptr &o) { return p == o.p; } + bool operator != (const shared_ptr &o) { return p != o.p; } + + static T* get_empty() { return v::get_empty (); } + void reference() { v::reference (p); } + void destroy() { v::destroy (p); } + void set_user_data (hb_user_data_key_t *key, + void *value, + hb_destroy_func_t destroy, + hb_bool_t replace) { v::set_user_data (p, key, value, destroy, replace); } + void * get_user_data (hb_user_data_key_t *key) { return v::get_user_data (p, key); } + + private: + T *p; +}; + +template +struct vtable_t +{ + static constexpr auto get_empty = _get_empty; + static constexpr auto reference = _reference; + static constexpr auto destroy = _destroy; + static constexpr auto set_user_data = _set_user_data; + static constexpr auto get_user_data = _get_user_data; +}; + +#define HB_DEFINE_VTABLE(name) \ + template<> \ + struct vtable \ + : vtable_t {} + +HB_DEFINE_VTABLE (buffer); +HB_DEFINE_VTABLE (blob); +HB_DEFINE_VTABLE (face); +HB_DEFINE_VTABLE (font); +HB_DEFINE_VTABLE (font_funcs); +HB_DEFINE_VTABLE (map); +HB_DEFINE_VTABLE (set); +HB_DEFINE_VTABLE (shape_plan); +HB_DEFINE_VTABLE (unicode_funcs); + +#undef HB_DEFINE_VTABLE + + +} // namespace hb + +#endif /* __cplusplus */ + +#endif /* HB_CPLUSPLUS_HH */ diff --git a/src/meson.build b/src/meson.build index fdbf3c614..fda1ab648 100644 --- a/src/meson.build +++ b/src/meson.build @@ -227,6 +227,7 @@ hb_base_headers = files( 'hb-blob.h', 'hb-buffer.h', 'hb-common.h', + 'hb-cplusplus.hh', 'hb-deprecated.h', 'hb-draw.h', 'hb-face.h', diff --git a/src/test-map.cc b/src/test-map.cc index 44500ef45..3f81e8c3a 100644 --- a/src/test-map.cc +++ b/src/test-map.cc @@ -20,7 +20,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * */ #include "hb.hh" diff --git a/src/test-set.cc b/src/test-set.cc index bcff05604..983a15910 100644 --- a/src/test-set.cc +++ b/src/test-set.cc @@ -20,13 +20,11 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * */ #include "hb.hh" #include "hb-set.hh" - int main (int argc, char **argv) { diff --git a/test/api/test-c.c b/test/api/test-c.c index b4518adbc..59eef4242 100644 --- a/test/api/test-c.c +++ b/test/api/test-c.c @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -/* This file tests that all headers can be included from .c files */ +/* This file tests that all headers can be included from C files */ #ifdef HAVE_CONFIG_H diff --git a/test/api/test-cplusplus.cc b/test/api/test-cplusplus.cc index 3313d7460..d23e794c4 100644 --- a/test/api/test-cplusplus.cc +++ b/test/api/test-cplusplus.cc @@ -1,5 +1,6 @@ /* * Copyright © 2011 Google, Inc. + * Copyright © 2022 Behdad Esfahbod * * This is part of HarfBuzz, a text shaping library. * @@ -24,7 +25,86 @@ * Google Author(s): Behdad Esfahbod */ -/* This file tests that all headers can be included from .cc files */ +/* This file tests that all headers can be included from C++ files, + * as well as test the C++ API. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_GLIB +#include +#endif + +#ifdef HAVE_ICU +#include +#endif + +#ifdef HAVE_FREETYPE +#include +#endif + +#ifdef HAVE_UNISCRIBE +#include +#endif + +#ifdef HAVE_CORETEXT +#include +#endif -#include "test-c.c" +/* Test C++ API. */ + +#include "hb-cplusplus.hh" + +#include +#include + +int +main () +{ + hb_buffer_t *b = hb_buffer_create (); + hb::shared_ptr pb {b}; + + /* Test copy-construction. */ + assert (bool (pb)); + hb::shared_ptr pb2 {pb}; + assert (bool (pb2)); + assert (bool (pb)); + + /* Test move-construction. */ + assert (bool (pb2)); + hb::shared_ptr pb4 {std::move (pb2)}; + assert (!bool (pb2)); + assert (bool (pb4)); + + /* Test copy-assignment. */ + hb::shared_ptr pb3; + assert (!bool (pb3)); + pb3 = pb; + assert (bool (pb3)); + assert (bool (pb)); + + /* Test move-assignment. */ + assert (bool (pb)); + pb2 = std::move (pb); + assert (!bool (pb)); + + pb.reference (); + pb.destroy (); + + pb3.reference (); + pb3.destroy (); + + pb3.swap (pb4); + + hb_user_data_key_t key; + pb.set_user_data (&key, b, nullptr, true); + (void) pb.get_user_data (&key); + + return pb == pb.get_empty () || pb == pb2; +}