Anklang-0.3.0.dev797+g4e3241f3 anklang-0.3.0.dev797+g4e3241f3
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
server.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 "server.hh"
3#include "jsonipc/jsonipc.hh"
4#include "crawler.hh"
5#include "platform.hh"
6#include "properties.hh"
7#include "serialize.hh"
8#include "main.hh"
9#include "driver.hh"
10#include "utils.hh"
11#include "project.hh"
12#include "path.hh"
13#include "sndfile.hh"
14#include "wave.hh"
15#include "internal.hh"
16#include <atomic>
17
18namespace Ase {
19
20// == ServerImpl ==
21static constexpr size_t telemetry_size = 4 * 1024 * 1024;
22
23ServerImpl *SERVER = nullptr;
24
25ServerImpl::ServerImpl () :
26 telemetry_arena (telemetry_size)
27{
28 assert_return (telemetry_arena.reserved() >= telemetry_size);
29 Block telemetry_header = telemetry_arena.allocate (64);
30 assert_return (telemetry_arena.location() == uint64 (telemetry_header.block_start));
31 const uint8_t header_sentinel[64] = {
32 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
33 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,
34 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b,
35 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
36 };
37 assert_return (telemetry_header.block_length == sizeof (header_sentinel));
38 memcpy (telemetry_header.block_start, header_sentinel, telemetry_header.block_length);
39 if (!SERVER)
40 SERVER = this;
41}
42
43ServerImpl::~ServerImpl ()
44{
45 fatal_error ("ServerImpl references must persist");
46 if (SERVER == this)
47 SERVER = nullptr;
48}
49
51ServerImpl::get_version ()
52{
53 return ase_version();
54}
55
57ServerImpl::get_build_id ()
58{
59 return ase_build_id();
60}
61
63ServerImpl::get_opus_version ()
64{
65 return wave_writer_opus_version();
66}
67
69ServerImpl::get_flac_version ()
70{
71 return wave_writer_flac_version();
72}
73
75ServerImpl::get_sndfile_version ()
76{
77 return libsndfile_version();
78}
79
80void
81ServerImpl::shutdown ()
82{
83 // defer quit() slightly, so remote calls are still completed
84 main_loop->add ([] () { main_loop->quit (0); }, std::chrono::milliseconds (5), LoopPriority::NORMAL);
85}
86
87ProjectP
88ServerImpl::last_project ()
89{
90 return Project::last_project();
91}
92
93ProjectP
94ServerImpl::create_project (String projectname)
95{
96 return ProjectImpl::create (projectname);
97}
98
100ServerImpl::list_preferences ()
101{
102 const CStringS list = Preference::list();
103 return { std::begin (list), std::end (list) };
104}
105
106PropertyP
107ServerImpl::access_preference (const String &ident)
108{
109 return Preference::find (ident);
110}
111
112ServerImplP
113ServerImpl::instancep ()
114{
115 static ServerImplP *sptr = new ServerImplP (std::make_shared<ServerImpl>());
116 return *sptr;
117}
118
119bool
120ServerImpl::set_data (const String &key, const Value &value)
121{
122 const String ckey = canonify_key (key);
123 if (ckey.size() && ckey[0] != '_')
124 {
125 const String filename = Path::join (Path::xdg_dir ("CONFIG"), "anklang", ckey);
126 emit_event ("data", key);
127 return Path::stringwrite (filename, value.as_string());
128 }
129 else
130 return GadgetImpl::set_data (ckey, value);
131}
132
133Value
134ServerImpl::get_data (const String &key) const
135{
136 const String ckey = canonify_key (key);
137 if (ckey.size() && ckey[0] != '_')
138 {
139 const String filename = Path::join (Path::xdg_dir ("CONFIG"), "anklang", ckey);
140 return Path::stringread (filename);
141 }
142 else
143 return GadgetImpl::get_data (ckey);
144}
145
146// == Server ==
147ServerP
148Server::instancep ()
149{
150 return ServerImpl::instancep();
151}
152
153Server&
154Server::instance ()
155{
156 return *instancep();
157}
158
159// == FileCrawler ==
160ResourceCrawlerP
161Server::dir_crawler (const String &cwd)
162{
163 return FileCrawler::make_shared (cwd, true, false);
164}
165
166ResourceCrawlerP
167Server::url_crawler (const String &url)
168{
169 if (App.web_socket_server) {
170 String dir = App.web_socket_server->map_url (url);
171 if (!dir.empty())
172 return FileCrawler::make_shared (dir, false, false);
173 }
174 return nullptr;
175}
176
177String
178Server::engine_stats ()
179{
180 const String s = "Unused"; // TODO: get stats from trkn
181 printerr ("Server::engine_stats:\n%s\n", s);
182 return s;
183}
184
185void
186Server::exit_program (int status)
187{
188 main_loop->quit (status);
189}
190
191// == Choice ==
192Choice::Choice (String ident_, String label_, String blurb_, String notice_, String warning_) :
193 ident (ident_.empty() ? string_to_identifier (label_) : ident_),
194 label (label_), blurb (blurb_), notice (notice_), warning (warning_)
195{
196 assert_return (ident.empty() == false);
197}
198
199Choice::Choice (String ident_, IconString icon_, String label_, String blurb_, String notice_, String warning_) :
200 ident (ident_.empty() ? string_to_identifier (label_) : ident_),
201 icon (icon_), label (label_), blurb (blurb_), notice (notice_), warning (warning_)
202{
203 assert_return (ident.empty() == false);
204}
205
206Choice::Choice (IconString icon_, String label_, String blurb_) :
207 Choice ("", icon_, label_, blurb_)
208{}
209
210ChoiceS&
211operator+= (ChoiceS &choices, Choice &&newchoice)
212{
213 choices.push_back (std::move (newchoice));
214 return choices;
215}
216
217// == Error ==
219const char*
221{
222 switch (error)
223 {
224 // errno aliases are left to strerror
225 case Error::NONE: return _("OK");
226 // Ase specific errors
227 case Error::INTERNAL: return _("Internal error (please report)");
228 // file errors
229 case Error::FILE_EOF: return _("End of file");
230 case Error::FILE_OPEN_FAILED: return _("Open failed");
231 case Error::FILE_SEEK_FAILED: return _("Seek failed");
232 case Error::FILE_READ_FAILED: return _("Read failed");
233 case Error::FILE_WRITE_FAILED: return _("Write failed");
234 // content errors
235 case Error::PARSE_ERROR: return _("Parsing error");
236 case Error::NO_HEADER: return _("Failed to detect header");
237 case Error::NO_SEEK_INFO: return _("Failed to retrieve seek information");
238 case Error::NO_DATA_AVAILABLE: return _("No data available");
239 case Error::DATA_CORRUPT: return _("Data corrupt");
240 case Error::WRONG_N_CHANNELS: return _("Wrong number of channels");
241 case Error::FORMAT_INVALID: return _("Invalid format");
242 case Error::FORMAT_UNKNOWN: return _("Unknown format");
243 case Error::DATA_UNMATCHED: return _("Requested data values unmatched");
244 case Error::CODEC_FAILURE: return _("Codec failure");
245 case Error::BROKEN_ARCHIVE: return _("Broken archive");
246 case Error::BAD_PROJECT: return _("Not a valid project");
247 case Error::NO_PROJECT_DIR: return _("Missing project directory");
248 // Device errors
249 case Error::DEVICE_NOT_AVAILABLE: return _("No device (driver) available");
250 case Error::DEVICE_ASYNC: return _("Device not async capable");
251 case Error::DEVICE_BUSY: return _("Device busy");
252 case Error::DEVICE_FORMAT: return _("Failed to configure device format");
253 case Error::DEVICE_BUFFER: return _("Failed to configure device buffer");
254 case Error::DEVICE_LATENCY: return _("Failed to configure device latency");
255 case Error::DEVICE_CHANNELS: return _("Failed to configure number of device channels");
256 case Error::DEVICE_FREQUENCY: return _("Failed to configure device frequency");
257 case Error::DEVICES_MISMATCH: return _("Device configurations mismatch");
258 // miscellaneous errors
259 case Error::WAVE_NOT_FOUND: return _("No such wave");
260 case Error::UNIMPLEMENTED: return _("Functionality not implemented");
261 case Error::INVALID_PROPERTY: return _("Invalid object property");
262 case Error::INVALID_MIDI_CONTROL: return _("Invalid MIDI control type");
263 case Error::OPERATION_BUSY: return _("Operation already in prgress");
264 default:
265 return strerror (int (error));
266 }
267}
268
269// Map errno onto Ase::Error.
270Error
271ase_error_from_errno (int sys_errno, Error fallback)
272{
273 if (sys_errno < int (Error::INTERNAL))
274 return Error (sys_errno); // Error includes errnos
275 else
276 return fallback;
277}
278
279String
280ServerImpl::error_blurb (Error error) const
281{
282 return ase_error_blurb (error);
283}
284
285// == MusicalTuning ==
286static EnumInfo
287musical_tuning_info (MusicalTuning musicaltuning)
288{
289 switch (musicaltuning)
290 {
291 // Equal Temperament: http://en.wikipedia.org/wiki/Equal_temperament
292 case MusicalTuning::OD_12_TET:
293 return { _("12 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
294 _("The most common tuning system for modern Western music, "
295 "is the twelve-tone equal temperament, abbreviated as 12-TET, "
296 "which divides the octave into 12 equal parts.") };
297 case MusicalTuning::OD_7_TET:
298 return { _("7 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
299 _("A fairly common tuning system is the seven-tone equal temperament tuning system, "
300 "abbreviated as 7-TET. It divides the octave into 7 equal parts using 171 cent steps.") };
301 case MusicalTuning::OD_5_TET:
302 return { _("5 Tone Equal Temperament"), // http://en.wikipedia.org/wiki/Equal_temperament
303 _("A fairly common tuning system is the five-tone equal temperament tuning system, "
304 "abbreviated as 5-TET. It divides the octave into 5 equal parts using 240 cent steps.") };
305 // Rational Intonation: http://en.wikipedia.org/wiki/Just_intonation
306 case MusicalTuning::DIATONIC_SCALE:
307 return { _("Diatonic Scale"), // http://en.wikipedia.org/wiki/Diatonic_scale
308 _("In music theory, a diatonic scale (also: heptatonia prima) is a seven-note "
309 "musical scale comprising five whole-tone and two half-tone steps. "
310 "The half tones are maximally separated, so between two half-tone steps "
311 "there are either two or three whole tones, repeating per octave.") }; // Werckmeister I
312 case MusicalTuning::INDIAN_SCALE:
313 return { _("Indian Scale"), // http://en.wikipedia.org/wiki/Just_intonation#Indian_scales
314 _("Diatonic scale used in Indian music with wolf interval at Dha, close to 3/2") };
315 case MusicalTuning::PYTHAGOREAN_TUNING:
316 return { _("Pythagorean Tuning"), // http://en.wikipedia.org/wiki/Pythagorean_tuning
317 _("Pythagorean tuning is the oldest way of tuning the 12-note chromatic scale, "
318 "in which the frequency relationships of all intervals are based on the ratio 3:2. "
319 "Its discovery is generally credited to Pythagoras.") };
320 case MusicalTuning::PENTATONIC_5_LIMIT:
321 return { _("Pentatonic 5-limit"), // http://en.wikipedia.org/wiki/Pentatonic_scale
322 _("Pentatonic scales are used in modern jazz and pop/rock contexts "
323 "because they work exceedingly well over several chords diatonic "
324 "to the same key, often better than the parent scale.") };
325 case MusicalTuning::PENTATONIC_BLUES:
326 return { _("Pentatonic Blues"), // http://en.wikipedia.org/wiki/Pentatonic_scale
327 _("The blues scale is the minor pentatonic with an additional augmented fourth, "
328 "which is referred to as the \"blues note\".") };
329 case MusicalTuning::PENTATONIC_GOGO:
330 return { _("Pentatonic Gogo"), // http://en.wikipedia.org/wiki/Pentatonic_scale
331 _("The Pentatonic Gogo scale is an anhemitonic pentatonic scale used to tune the "
332 "instruments of the Gogo people of Tanzania.") };
333 // Meantone Temperament: http://en.wikipedia.org/wiki/Meantone_temperament
334 case MusicalTuning::QUARTER_COMMA_MEANTONE:
335 return { _("Quarter-Comma Meantone"), // http://en.wikipedia.org/wiki/Quarter-comma_meantone
336 _("Quarter-comma meantone was the most common meantone temperament in the "
337 "sixteenth and seventeenth centuries and sometimes used later.") }; // Werckmeister II
338 case MusicalTuning::SILBERMANN_SORGE:
339 return { _("Silbermann-Sorge Temperament"), // http://de.wikipedia.org/wiki/Silbermann-Sorge-Temperatur
340 _("The Silbermann-Sorge temperament is a meantone temperament used for "
341 "Baroque era organs by Gottfried Silbermann.") };
342 // Well Temperament: http://en.wikipedia.org/wiki/Well_temperament
343 case MusicalTuning::WERCKMEISTER_3:
344 return { _("Werckmeister III"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
345 _("This tuning uses mostly pure (perfect) fifths, as in Pythagorean tuning, but each "
346 "of the fifths C-G, G-D, D-A and B-F# is made smaller, i.e. tempered by 1/4 comma. "
347 "Werckmeister designated this tuning as particularly suited for playing chromatic music.") };
348 case MusicalTuning::WERCKMEISTER_4:
349 return { _("Werckmeister IV"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
350 _("In this tuning the fifths C-G, D-A, E-B, F#-C#, and Bb-F are tempered narrow by 1/3 comma, "
351 "and the fifths G#-D# and Eb-Bb are widened by 1/3 comma. The other fifths are pure. "
352 "Most of its intervals are close to sixth-comma meantone. "
353 "Werckmeister designed this tuning for playing mainly diatonic music.") };
354 case MusicalTuning::WERCKMEISTER_5:
355 return { _("Werckmeister V"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
356 _("In this tuning the fifths D-A, A-E, F#-C#, C#-G#, and F-C are narrowed by 1/4 comma, "
357 "and the fifth G#-D# is widened by 1/4 comma. The other fifths are pure. "
358 "This temperament is closer to equal temperament than Werckmeister III or IV.") };
359 case MusicalTuning::WERCKMEISTER_6:
360 return { _("Werckmeister VI"), // http://en.wikipedia.org/wiki/Werckmeister_temperament
361 _("This tuning is also known as Septenarius tuning is based on a division of the monochord "
362 "length into 196 = 7 * 7 * 4 parts. "
363 "The resulting scale has rational frequency relationships, but in practice involves pure "
364 "and impure sounding fifths. "
365 "Werckmeister described the Septenarius as a \"temperament which has nothing at all to do "
366 "with the divisions of the comma, nevertheless in practice so correct that one can be really "
367 "satisfied with it\".") };
368 case MusicalTuning::KIRNBERGER_3:
369 return { _("Kirnberger III"), // http://en.wikipedia.org/wiki/Johann_Philipp_Kirnberger_temperament
370 _("Kirnberger's method of compensating for and closing the circle of fifths is to split the \"wolf\" "
371 "interval known to those who have used meantone temperaments between four fifths instead, "
372 "allowing for four 1/4-comma wolves to take their place. "
373 "1/4-comma wolves are used extensively in meantone and are much easier to tune and to listen to. "
374 "Therefore, only one third remains pure (between C and E).") };
375 case MusicalTuning::YOUNG:
376 return { _("Young Temperament"), // http://en.wikipedia.org/wiki/Young_temperament
377 _("Thomas Young devised a form of musical tuning to make the harmony most perfect in those keys which "
378 "are the most frequently used (give better major thirds in those keys), but to not have any unplayable keys. "
379 "This is attempted by tuning upwards from C a sequence of six pure fourths, "
380 "as well as six equally imperfect fifths.") };
381 default:
382 return { "", "" };
383 }
384}
385static bool musical_tuning_info__ = EnumInfo::impl (musical_tuning_info);
386
387String
388ServerImpl::musical_tuning_blurb (MusicalTuning musicaltuning) const
389{
390 return EnumInfo::value_info (musicaltuning).blurb;
391}
392
393String
394ServerImpl::musical_tuning_label (MusicalTuning musicaltuning) const
395{
396 return EnumInfo::value_info (musicaltuning).label;
397}
398
399static std::atomic<uint> user_note_id = 1;
400
401uint64
402ServerImpl::user_note (const String &text, const String &channel, UserNote::Flags flags, const String &rest)
403{
404 UserNote unote { user_note_id++, flags, channel.empty() ? "misc" : channel, text, rest };
405 ValueR vrec;
406 json_parse (json_stringify (unote), vrec);
407 this->emit_event ("usernote", "", vrec);
408 String s;
409 s += string_format ("%s: usernote[%04x]: %s: %s", program_alias(), unote.noteid, unote.channel, unote.text);
410 if (!unote.rest.empty())
411 s += " (" + unote.rest + ")";
412 printerr ("%s\n", string_replace (s, "\n", "\t"));
413 return unote.noteid;
414}
415
416bool
417ServerImpl::user_reply (uint64 noteid, uint r)
418{
419 return false; // unhandled
420}
421
422ServerImpl::Block
423ServerImpl::telemem_allocate (uint32 length) const
424{
425 return telemetry_arena.allocate (length);
426}
427
428void
429ServerImpl::telemem_release (Block telememblock) const
430{
431 telemetry_arena.release (telememblock);
432}
433
434ptrdiff_t
435ServerImpl::telemem_start () const
436{
437 return telemetry_arena.location();
438}
439
440static bool
441validate_telemetry_segments (const TelemetrySegmentS &segments, size_t *payloadlength)
442{
443 *payloadlength = 0;
444 const TelemetrySegment *last = nullptr;
445 for (const auto &seg : segments)
446 {
447 if (last && seg.offset < last->offset + last->length)
448 return false; // check sorting and non-overlapping
449 if (seg.offset < 0 || (seg.offset & 3) || seg.length <= 0 || (seg.length & 3) ||
450 size_t (seg.offset + seg.length) > telemetry_size)
451 return false;
452 *payloadlength += seg.length;
453 last = &seg;
454 }
455 return true;
456}
457
458ASE_CLASS_DECLS (TelemetryPlan);
459class TelemetryPlan : public std::enable_shared_from_this<TelemetryPlan> {
460public:
461 int32 interval_ms_ = -1;
462 LoopID timerid_ = LoopID::INVALID;
463 JsonapiBinarySender send_blob_;
464 TelemetrySegmentS segments_;
465 const char *telemem_ = nullptr;
466 String payload_;
467 void send_telemetry();
468 void setup (const char *start, size_t payloadlength, const TelemetrySegmentS &plan, int32 interval_ms);
470};
471static CustomDataKey<TelemetryPlanP> telemetry_key;
472
473bool
474ServerImpl::broadcast_telemetry (const TelemetrySegmentS &segments, int32 interval_ms)
475{
476 size_t payloadlength = 0;
477 if (!validate_telemetry_segments (segments, &payloadlength))
478 {
479 warning ("%s: invalid segment list", "Ase::ServerImpl::broadcast_telemetry");
480 return false;
481 }
482 CustomDataContainer *cdata = jsonapi_connection_data();
483 if (!cdata)
484 {
485 warning ("%s: cannot broadcast telemetry without jsonapi connection", "Ase::ServerImpl::broadcast_telemetry");
486 return false;
487 }
488 TelemetryPlanP tplan = cdata->get_custom_data (&telemetry_key);
489 if (!tplan)
490 {
492 cdata->set_custom_data (&telemetry_key, tplan);
493 tplan->send_blob_ = jsonapi_connection_sender();
494 }
495 tplan->setup ((const char*) telemetry_arena.location(), payloadlength, segments, interval_ms);
496 return true;
497}
498
499void
500TelemetryPlan::setup (const char *start, size_t payloadlength, const TelemetrySegmentS &segments, int32 interval_ms)
501{
502 if (timerid_ == LoopID::INVALID || interval_ms_ != interval_ms)
503 {
504 if (timerid_ != LoopID::INVALID)
505 main_loop->cancel (timerid_);
506 auto tplan = shared_from_this();
507 auto send_telemetry = [tplan] () { tplan->send_telemetry(); return true; };
508 interval_ms_ = interval_ms;
509 timerid_ = interval_ms <= 0 || segments.empty() ? LoopID::INVALID : main_loop->add (send_telemetry, std::chrono::milliseconds (interval_ms));
510 }
511 if (timerid_ != LoopID::INVALID)
512 {
513 telemem_ = start;
514 segments_ = segments;
515 payload_.resize (payloadlength);
516 }
517 else
518 {
519 telemem_ = nullptr;
520 segments_ = {};
521 payload_.clear();
522 }
523}
524
525void
526TelemetryPlan::send_telemetry ()
527{
528 // Safety check: don't send if telemetry memory or segments are invalid
529 if (!telemem_ || segments_.empty() || payload_.empty())
530 return;
531 char *data = &payload_[0];
532 size_t datapos = 0;
533 for (const auto &seg : segments_) // offsets and lengths were validated earlier
534 {
535 memcpy (data + datapos, telemem_ + seg.offset, seg.length);
536 datapos += seg.length;
537 }
538 // send_blob_ handles the case where the connection is closed (returns false)
539 (void) send_blob_ (payload_);
540}
541
542TelemetryPlan::~TelemetryPlan()
543{
544 if (timerid_ != LoopID::INVALID)
545 {
546 // Only cancel if the loop is still running
547 if (!main_loop->has_quit())
548 main_loop->cancel (timerid_);
549 timerid_ = LoopID::INVALID;
550 }
551}
552
553} // Ase
T begin(T... args)
DataListContainer - typesafe storage and retrieval of arbitrary members.
Definition utils.hh:86
T get_custom_data(CustomDataKey< T > *key) const
Retrieve contents of the custom keyed data member, returns DataKey::fallback if nothing was set.
Definition utils.hh:102
void set_custom_data(CustomDataKey< T > *key, T data)
Assign data to the custom keyed data member, deletes any previously set data.
Definition utils.hh:99
CustomDataKey objects are used to identify and manage custom data members of CustomDataContainer obje...
Definition utils.hh:70
bool broadcast_telemetry(const TelemetrySegmentS &plan, int32 interval_ms) override
Broadcast telemetry memory segments to the current Jsonipc connection.
Definition server.cc:474
Central singleton, serves as API entry point.
Definition api.hh:392
T clear(T... args)
T data(T... args)
T empty(T... args)
T end(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 _(...)
Retrieve the translation of a C or C++ string.
Definition internal.hh:18
memcpy
The Anklang C++ API namespace.
Definition api.hh:9
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
String string_to_identifier(const String &input)
Force lower case, alphanumerics + underscore and non-digit start.
Definition strings.cc:54
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
Definition cxxaux.hh:25
int32_t int32
A 32-bit signed integer.
Definition cxxaux.hh:28
bool json_parse(const String &jsonstring, T &target)
Parse a well formed JSON string and assign contents to target.
Definition serialize.hh:538
Error
Enum representing Error states.
Definition api.hh:22
const char * ase_error_blurb(Error error)
Describe Error condition.
Definition server.cc:220
String string_replace(const String &input, const String &marker, const String &replacement, size_t maxn)
Replace substring marker in input with replacement, at most maxn times.
Definition strings.cc:1144
ChoiceS & operator+=(ChoiceS &choices, Choice &&newchoice)
Convenience ChoiceS construction helper.
Definition server.cc:211
String program_alias()
Retrieve the program name as used for logging or debug messages.
Definition platform.cc:817
const char * ase_version()
Provide a string containing the package version.
Definition platform.cc:803
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
uint32_t uint32
A 32-bit unsigned integer.
Definition cxxaux.hh:24
uint32_t uint
Provide 'uint' as convenience type.
Definition cxxaux.hh:18
String json_stringify(const T &source, Writ::Flags flags=Writ::Flags(0))
Create JSON string from source.
Definition serialize.hh:530
MusicalTuning
Musical tunings, see: http://en.wikipedia.org/wiki/Musical_tuning.
Definition api.hh:83
const char * ase_build_id()
Provide a string containing the ASE library build id.
Definition platform.cc:809
unsigned long long uint64
T resize(T... args)
T size(T... args)
typedef uint8_t
strerror
Representation of one possible choice for selection properties.
Definition api.hh:96
uint64 location() const
Address of memory area.
Definition memory.cc:340
Block allocate(uint32 length) const
Create a memory block from cache-line aligned memory area, MT-Unsafe.
Definition memory.cc:371
void release(Block allocatedblock) const
Realease a previously allocated block, MT-Unsafe.
Definition memory.cc:380
Value type used to interface with various property types.
Definition value.hh:54
String as_string() const
Convert Value to a string, not very useful for RECORD or ARRAY.
Definition value.cc:95
typedef size_t