Imported Upstream version 8.2.2
[platform/upstream/harfbuzz.git] / test / threads / hb-subset-threads.cc
1 #include <cassert>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <cstring>
5 #include <thread>
6 #include <condition_variable>
7 #include <vector>
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include "hb-subset.h"
14
15 enum operation_t
16 {
17   subset_codepoints,
18   subset_glyphs
19 };
20
21 #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
22
23 struct test_input_t
24 {
25   const char *font_path;
26   const unsigned max_subset_size;
27 } default_tests[] =
28 {
29   {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000},
30   {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000},
31   {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000},
32   {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000},
33   {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000},
34   {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000},
35   {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000},
36 };
37
38
39 static test_input_t *tests = default_tests;
40 static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
41
42
43 // https://en.cppreference.com/w/cpp/thread/condition_variable/wait
44 static std::condition_variable cv;
45 static std::mutex cv_m;
46 static bool ready = false;
47
48 static unsigned num_repetitions = 1;
49 static unsigned num_threads = 3;
50
51 static void AddCodepoints(const hb_set_t* codepoints_in_font,
52                           unsigned subset_size,
53                           hb_subset_input_t* input)
54 {
55   auto *unicodes = hb_subset_input_unicode_set (input);
56   hb_codepoint_t cp = HB_SET_VALUE_INVALID;
57   for (unsigned i = 0; i < subset_size; i++) {
58     if (!hb_set_next (codepoints_in_font, &cp)) return;
59     hb_set_add (unicodes, cp);
60   }
61 }
62
63 static void AddGlyphs(unsigned num_glyphs_in_font,
64                unsigned subset_size,
65                hb_subset_input_t* input)
66 {
67   auto *glyphs = hb_subset_input_glyph_set (input);
68   for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
69     hb_set_add (glyphs, i);
70   }
71 }
72
73 static void subset (operation_t operation,
74                     const test_input_t &test_input,
75                     hb_face_t *face)
76 {
77   // Wait till all threads are ready.
78   {
79     std::unique_lock<std::mutex> lk (cv_m);
80     cv.wait(lk, [] {return ready;});
81   }
82
83   unsigned subset_size = test_input.max_subset_size;
84
85   hb_subset_input_t* input = hb_subset_input_create_or_fail ();
86   assert (input);
87
88   switch (operation)
89   {
90     case subset_codepoints:
91     {
92       hb_set_t* all_codepoints = hb_set_create ();
93       hb_face_collect_unicodes (face, all_codepoints);
94       AddCodepoints(all_codepoints, subset_size, input);
95       hb_set_destroy (all_codepoints);
96     }
97     break;
98
99     case subset_glyphs:
100     {
101       unsigned num_glyphs = hb_face_get_glyph_count (face);
102       AddGlyphs(num_glyphs, subset_size, input);
103     }
104     break;
105   }
106
107   for (unsigned i = 0; i < num_repetitions; i++)
108   {
109     hb_face_t* subset = hb_subset_or_fail (face, input);
110     assert (subset);
111     hb_face_destroy (subset);
112   }
113
114   hb_subset_input_destroy (input);
115 }
116
117 static void test_operation (operation_t operation,
118                             const char *operation_name,
119                             const test_input_t &test_input)
120 {
121   char name[1024] = "subset";
122   const char *p;
123   strcat (name, "/");
124   p = strrchr (test_input.font_path, '/');
125   strcat (name, p ? p + 1 : test_input.font_path);
126   strcat (name, "/");
127   strcat (name, operation_name);
128
129   printf ("Testing %s\n", name);
130
131   hb_face_t *face;
132   {
133     hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
134     assert (blob);
135     face = hb_face_create (blob, 0);
136     hb_blob_destroy (blob);
137   }
138
139   std::vector<std::thread> threads;
140   for (unsigned i = 0; i < num_threads; i++)
141     threads.push_back (std::thread (subset, operation, test_input, face));
142
143   {
144     std::unique_lock<std::mutex> lk (cv_m);
145     ready = true;
146   }
147   cv.notify_all();
148
149   for (unsigned i = 0; i < num_threads; i++)
150     threads[i].join ();
151
152   hb_face_destroy (face);
153 }
154
155 int main(int argc, char** argv)
156 {
157   if (argc > 1)
158     num_threads = atoi (argv[1]);
159   if (argc > 2)
160     num_repetitions = atoi (argv[2]);
161
162   if (argc > 4)
163   {
164     num_tests = argc - 3;
165     tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
166     for (unsigned i = 0; i < num_tests; i++)
167     {
168       tests[i].font_path = argv[3 + i];
169     }
170   }
171
172   printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
173   for (unsigned i = 0; i < num_tests; i++)
174   {
175     auto& test_input = tests[i];
176     test_operation (subset_codepoints, "codepoints", test_input);
177     test_operation (subset_glyphs, "glyphs", test_input);
178   }
179
180   if (tests != default_tests)
181     free (tests);
182 }