Anklang-0.3.0.dev595+g65331842 anklang-0.3.0.dev595+g65331842
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
utils.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "utils.hh"
3#include "platform.hh"
4#include "strings.hh"
5#include "memory.hh"
6#include "unicode.hh"
7#include "internal.hh"
8#include <signal.h>
9#include <sys/time.h>
10#include <poll.h>
11#include <fcntl.h>
12#include <cmath>
13#include <atomic>
14#include <unistd.h>
15
16namespace Ase {
17
18// == i18n & gettext ==
19const char*
20ase_gettext (const String &untranslated)
21{
22 CString translated = untranslated;
23 return translated.c_str(); // relies on global CString storage
24}
25
26// == Date & Time ==
28now_strftime (const String &format)
29{
30 std::time_t t = std::time (nullptr);
31 char buffer[4096] = { 0, };
32 if (std::strftime (buffer, sizeof (buffer), format.c_str(), std::localtime (&t)))
33 return buffer;
34 return "";
35}
36
37// == MakeIcon ==
38namespace MakeIcon {
39
41IconString
42KwIcon (const String &keywords)
43{
44 static const String keyword_charset = string_set_ascii_alnum() + "_-";
45 String s = keywords;
46 return_unless (!s.empty(), {});
47 StringS words = string_split_any (keywords, " ,");
48 Aux::erase_all (words, [] (const String &word) {
49 if (word.empty()) return true;
50 if (!string_is_canonified (word, keyword_charset))
51 {
52 warning ("%s: invalid icon keyword: '%s'", __func__, word);
53 return true;
54 }
55 return false;
56 });
57 IconString is;
58 is.assign (string_join (", ", words));
59 if (!is.empty() && is.find (',') == is.npos)
60 is += ","; // ensure comma in keyword list
61 return is;
62}
63
66operator""_icon (const char *key, size_t)
67{
68 return KwIcon (key);
69}
70
73UcIcon (const String &unicode)
74{
75 std::vector<uint32_t> codepoints;
76 if (utf8_to_unicode (unicode, codepoints) > 3 ||
77 (codepoints.size() >= 1 && !unicode_is_character (codepoints[0])) ||
78 (codepoints.size() >= 2 && !unicode_is_character (codepoints[1])) ||
79 (codepoints.size() >= 3 && !unicode_is_character (codepoints[2])))
80 warning ("%s: invalid icon unicode: '%s'", __func__, unicode);
81 IconString is;
82 is.assign (unicode);
83 return is;
84}
85
88operator""_uc (const char *key, size_t)
89{
90 return UcIcon (key);
91}
92
95SvgIcon (const String &svgdata)
96{
97 return_unless (!svgdata.empty(), {});
98 if (!string_startswith (svgdata, "<svg") || !string_startswith (svgdata, "<SVG"))
99 warning ("%s: invalid svg icon: %s…", __func__, svgdata.substr (0, 40));
100 IconString is;
101 is.assign (svgdata);
102 return is;
103}
104
105} // MakeIcon
106
107// == EventFd ==
108EventFd::EventFd () :
109 fds { -1, -1 }
110{}
111
112int
114{
115 if (opened())
116 return 0;
117 ASE_UNUSED long nflags;
118#ifdef HAVE_SYS_EVENTFD_H
119 do
120 fds[0] = eventfd (0 /*initval*/, EFD_CLOEXEC | EFD_NONBLOCK);
121 while (fds[0] < 0 && (errno == EAGAIN || errno == EINTR));
122#else
123 int err;
124 do
125 err = pipe2 (fds, O_CLOEXEC | O_NONBLOCK);
126 while (err < 0 && (errno == EAGAIN || errno == EINTR));
127 if (fds[1] >= 0)
128 {
129 nflags = fcntl (fds[1], F_GETFL, 0);
130 assert_return (nflags & O_NONBLOCK, -1);
131 nflags = fcntl (fds[1], F_GETFD, 0);
132 assert_return (nflags & FD_CLOEXEC, -1);
133 }
134#endif
135 if (fds[0] >= 0)
136 {
137 nflags = fcntl (fds[0], F_GETFL, 0);
138 assert_return (nflags & O_NONBLOCK, -1);
139 nflags = fcntl (fds[0], F_GETFD, 0);
140 assert_return (nflags & FD_CLOEXEC, -1);
141 return 0;
142 }
143 return -errno;
144}
145
146int
147EventFd::inputfd () // fd for POLLIN
148{
149 return fds[0];
150}
151
152bool
154{
155 return inputfd() >= 0;
156}
157
158bool
160{
161 struct pollfd pfd = { inputfd(), POLLIN, 0 };
162 int presult;
163 do
164 presult = poll (&pfd, 1, -1);
165 while (presult < 0 && (errno == EAGAIN || errno == EINTR));
166 return pfd.revents != 0;
167}
168
169void
171{
172 int err;
173#ifdef HAVE_SYS_EVENTFD_H
174 do
175 err = eventfd_write (fds[0], 1);
176 while (err < 0 && errno == EINTR);
177#else
178 char w = 'w';
179 do
180 err = write (fds[1], &w, 1);
181 while (err < 0 && errno == EINTR);
182#endif
183 // EAGAIN occours if too many wakeups are pending
184}
185
186void
188{
189 int err;
190#ifdef HAVE_SYS_EVENTFD_H
191 eventfd_t bytes8;
192 do
193 err = eventfd_read (fds[0], &bytes8);
194 while (err < 0 && errno == EINTR);
195#else
196 char buffer[512]; // 512 is POSIX pipe atomic read/write size
197 do
198 err = read (fds[0], buffer, sizeof (buffer));
199 while (err == 512 || (err < 0 && errno == EINTR));
200#endif
201 // EAGAIN occours if no wakeups are pending
202}
203
204EventFd::~EventFd ()
205{
206#ifdef HAVE_SYS_EVENTFD_H
207 close (fds[0]);
208#else
209 close (fds[0]);
210 close (fds[1]);
211#endif
212 fds[0] = -1;
213 fds[1] = -1;
214}
215
216// == CustomDataContainer ==
217CustomDataContainer::CustomDataEntry&
218CustomDataContainer::custom_data_entry (VirtualBase *key)
219{
220 if (!custom_data_)
221 custom_data_ = std::make_unique<CustomDataS> (1);
222 assert_return (key != nullptr, *custom_data_->end());
223 for (auto &e : *custom_data_)
224 if (e.key == key)
225 return e;
226 custom_data_->push_back ({ .key = key, });
227 return custom_data_->back();
228}
229
231CustomDataContainer::custom_data_get (VirtualBase *key) const
232{
233 if (custom_data_)
234 for (auto &e : *custom_data_)
235 if (e.key == key)
236 return e;
237 static std::any dummy;
238 return dummy;
239}
240
241bool
242CustomDataContainer::custom_data_del (VirtualBase *key)
243{
244 if (custom_data_)
245 return Aux::erase_first (*custom_data_, [key] (auto &e) { return key == e.key; });
246 return 0;
247 static_assert (sizeof (CustomDataContainer) == sizeof (void*));
248}
249
250void
251CustomDataContainer::custom_data_destroy()
252{
253 return_unless (custom_data_);
254 while (!custom_data_->empty())
255 {
256 std::any old;
257 std::swap (old, custom_data_->back());
258 custom_data_->pop_back();
259 // destroy old *after* removal from vector
260 }
261}
262
263CustomDataContainer::~CustomDataContainer()
264{
265 custom_data_destroy();
266}
267
268} // Ase
269
270#include "testing.hh"
271
272namespace { // Anon
273
274TEST_INTEGRITY (utils_tests);
275static void
276utils_tests()
277{
278 using namespace Ase;
279 TASSERT (uint16_swap_le_be (0x1234) == 0x3412);
280 TASSERT (uint32_swap_le_be (0xe23456f8) == 0xf85634e2);
281 TASSERT (uint64_swap_le_be (0xf2345678a1b2c3d4) == 0xd4c3b2a1785634f2);
282 std::vector<float> fv { 1, -2, 0, -0.5, 2, -1 };
283 bool b;
284 b = Aux::contains (fv, [] (auto v) { return v == 9; }); TASSERT (b == false);
285 b = Aux::contains (fv, [] (auto v) { return v == 2; }); TASSERT (b == true);
286 size_t j;
287 j = Aux::erase_all (fv, [] (auto v) { return fabs (v) == 2; });
288 TASSERT (j == 2 && fv == (std::vector<float> { 1, 0, -0.5, -1 }));
289 j = Aux::erase_first (fv, [] (auto v) { return fabs (v) == 1; });
290 TASSERT (j == 1 && fv == (std::vector<float> { 0, -0.5, -1 }));
291}
292
293} // Anon
#define EAGAIN
T assign(T... args)
bool opened()
Indicates whether eventfd has been opened.
Definition utils.cc:153
void flush()
Clear pending wakeups.
Definition utils.cc:187
int inputfd()
Returns the file descriptor for POLLIN.
Definition utils.cc:147
bool pollin()
Checks whether events are pending.
Definition utils.cc:159
int open()
Opens the eventfd and returns -errno.
Definition utils.cc:113
void wakeup()
Wakeup polling end.
Definition utils.cc:170
close
T empty(T... args)
errno
fabs
fcntl
T format(T... args)
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
Definition internal.hh:29
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
Definition internal.hh:73
#define TEST_INTEGRITY(FUNC)
Register func as an integrity test.
Definition internal.hh:79
T localtime(T... args)
size_t erase_all(C &container, const std::function< bool(typename C::value_type const &value)> &pred)
Erase all elements for which pred() is true in vector or list.
Definition utils.hh:281
size_t erase_first(C &container, const std::function< bool(typename C::value_type const &value)> &pred)
Erase first element for which pred() is true in vector or list.
Definition utils.hh:268
The Anklang C++ API namespace.
Definition api.hh:9
String string_join(const String &junctor, const StringS &strvec)
Join a number of strings.
Definition strings.cc:452
bool string_is_canonified(const String &string, const String &valid_chars)
Check if string_canonify() would modify string.
Definition strings.cc:90
size_t utf8_to_unicode(const char *str, uint32_t *codepoints)
Convert valid UTF-8 sequences to Unicode codepoints, invalid sequences are treated as Latin-1 charact...
Definition unicode.cc:221
constexpr bool unicode_is_character(uint32_t u)
Return whether u is not one of the 66 Unicode noncharacters.
Definition unicode.hh:67
const String & string_set_ascii_alnum()
Returns a string containing all of 0-9, A-Z and a-z.
Definition strings.cc:118
StringS string_split_any(const String &string, const String &splitchars, size_t maxn)
Split a string, using any of the splitchars as delimiter.
Definition strings.cc:365
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
bool string_startswith(const String &string, const String &fragment)
Returns whether string starts with fragment.
Definition strings.cc:846
poll
read
write
T strftime(T... args)
T substr(T... args)
T swap(T... args)
#define TASSERT(cond)
Unconditional test assertion, enters breakpoint if not fullfilled.
Definition testing.hh:24
T time(T... args)
IconString SvgIcon(const String &svgdata)
Create an IconString consisting of an SVG string.
Definition utils.cc:95
IconString UcIcon(const String &unicode)
Create an IconString consisting of a single/double unicode character.
Definition utils.cc:73
IconString KwIcon(const String &keywords)
Create an IconString consisting of keywords.
Definition utils.cc:42