ifw-daq 3.1.0
IFW Data Acquisition modules
Loading...
Searching...
No Matches
keyword.hpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup daq_ocm_libfits
4 * @copyright 2022 ESO - European Southern Observatory
5 *
6 * @brief Contains data structure for FITS keywords
7 */
8#ifndef DAQ_OCM_DAQ_FITS_KEYWORD_HPP_
9#define DAQ_OCM_DAQ_FITS_KEYWORD_HPP_
10
11#include <array>
12#include <cstdint>
13#include <iosfwd>
14#include <optional>
15#include <stdexcept>
16#include <string>
17#include <variant>
18#include <vector>
19
20#include <cfitsio/fitsio.h>
21
22namespace daq::fits {
23// Forward declarations
24enum KeywordType : uint8_t;
25class KeywordFormatter;
26
27namespace constants {
28/**
29 * FITS keyword record length.
30 */
31static constexpr std::size_t RECORD_LENGTH = 80u;
32/**
33 * FITS keyword name length.
34 */
35static constexpr std::size_t KEYWORD_NAME_LENGTH = 8u;
36/**
37 * ESO keyword prefix, up to and including trailing whitespace
38 */
39static constexpr std::string_view ESO_HIERARCH_PREFIX = "HIERARCH ESO ";
40/**
41 * Absolute maximum length of logical keyword assuming packed value-indicator `= ` and no value
42 */
43static constexpr std::size_t ESO_HIERARCH_MAX_NAME_LENGTH =
44 RECORD_LENGTH - ESO_HIERARCH_PREFIX.size() - 2u;
45/**
46 * Threshold where if name and formatted value >= this limit the packed formatting is used.
47 */
48static constexpr std::size_t ESO_HIERARCH_NAME_VALUE_PACKED_LIMIT = ESO_HIERARCH_MAX_NAME_LENGTH;
49
50/**
51 * FITS value indicator.
52 */
53static constexpr std::string_view VALUE_INDICATOR = "= ";
54/**
55 * Blank chars which is used to determine end of keyword record.
56 */
57static constexpr std::string_view BLANK_CHARS = std::string_view(" \0", 2);
58} // namespace constants
59
60/**
61 * Type of FITS keyword.
62 *
63 * FITS standard define two types: Value keywords and Commentary keywords.
64 *
65 * ESO conventions adds a third "ESO hiearchical keyword" which is strictly speaking a
66 * Commentary keyword with keyword name "HIERARCH".
67 */
68enum KeywordType : std::uint8_t {
69 /**
70 * A value keyword.
71 */
73 /**
74 * An ESO hiearchical keyword.
75 */
77 /**
78 * A commentary keyword, which are keywords that do not fall into the previous categories.
79 */
81};
82
84 std::string_view name;
86};
87
88/**
89 * Fits keyword type
90 *
91 * See https://heasarc.gsfc.nasa.gov/docs/software/fitsio/c/c_user/node52.html#ffdtyp
92 */
93enum class KeywordClass : int {
94 Structure = TYP_STRUC_KEY,
95 Compression = TYP_CMPRS_KEY,
96 Scale = TYP_SCAL_KEY,
97 Null = TYP_NULL_KEY,
98 Dim = TYP_DIM_KEY,
99 Range = TYP_RANG_KEY,
100 Unit = TYP_UNIT_KEY,
101 Disp = TYP_DISP_KEY,
102 HduId = TYP_HDUID_KEY,
103 Checksum = TYP_CKSUM_KEY,
104 Wcs = TYP_WCS_KEY,
105 RefSys = TYP_REFSYS_KEY,
106 Comment = TYP_COMM_KEY,
107 Continue = TYP_CONT_KEY,
108
109 User = TYP_USER_KEY,
110};
111
112/**
113 * @returns true if keyword type and names are equal.
114 * @relatesalso KeywordNameView
115 */
116bool operator==(KeywordNameView lhs, KeywordNameView rhs) noexcept;
117
118/**
119 * @returns true if keyword type and names are not equal.
120 * @relatesalso KeywordNameView
121 */
122bool operator!=(KeywordNameView lhs, KeywordNameView rhs) noexcept;
123
124/**
125 * Represents the literal 80-character FITS keyword record.
126 *
127 * @ingroup daq_ocm_libfits
128 */
129class LiteralKeyword final {
130public:
131 /**
132 * Decomposed components a literal keyword.
133 */
134 struct Components {
136
137 std::string_view name;
138 std::string_view value;
139 /**
140 * Comment may be empty
141 */
142 std::string_view comment;
143 };
144
145 /**
146 * Initializes an empty record (filled with ' ' characters)
147 */
148 LiteralKeyword() noexcept;
149
150 /**
151 * Construct literal keyword from a fixed size record.
152 *
153 * @param record FITS keyword record literal.
154 */
155 explicit LiteralKeyword(std::array<char, constants::RECORD_LENGTH> record);
156
157 /**
158 * Construct literal keyword from string_view.
159 *
160 * @note If string_view is empty this will be interpreted as the (valid) keyword " ".
161 *
162 * @param record literal keyword record.
163 *
164 * @throw std::invalid_argument if record is invalid (size() > 80).
165 */
166 explicit LiteralKeyword(std::string_view record);
167
168 LiteralKeyword(LiteralKeyword const& other) noexcept;
169 LiteralKeyword& operator=(LiteralKeyword const& other) noexcept;
170
171 /**
172 * @return Keyword type.
173 */
174 constexpr KeywordType GetType() const noexcept {
175 return m_components.type;
176 }
177
178 /**
179 * Query logical keyword name.
180 *
181 * The logical keyword name depends on the type of keyword:
182 *
183 * - Type::Value: Returns same value as GetName() but without trailing whitespaces.
184 * - Type::Eso: Returns the logical keyword name following "HIEARCH ESO" up to the first "=",
185 * without leading or trailing whitespaces.
186 * - Type::Commentary: Keywords that do not fall into
187 *
188 * @returns the logical keyword name which depends on the type of keyword and the type.
189 */
190 constexpr KeywordNameView GetName() const& noexcept {
191 return {m_components.name, m_components.type};
192 }
193 KeywordNameView GetName() && noexcept = delete;
194
195 /**
196 * @returns the FITS keyword record without trailing blank characters.
197 *
198 * @todo Rename to GetLogicalRecord?
199 */
200 std::string_view GetRecord() const& noexcept;
201 constexpr std::string_view GetRecord() && noexcept = delete;
202
203 /**
204 * Get components of the keyword in its literal form with insignifant whitespaces removed.
205 */
206 constexpr Components GetComponents() const& noexcept {
207 return m_components;
208 }
209
210private:
211 std::array<char, constants::RECORD_LENGTH> m_record;
212 // Components refer to m_record
213 Components m_components;
214};
215
217 LiteralKeyword::Components const& rhs) noexcept -> bool;
218
220 LiteralKeyword::Components const& rhs) noexcept -> bool;
221/**
222 * Sort by logical keyword name (not DICD sort)
223 *
224 * @relatesalso LiteralKeyword
225 * @ingroup daq_ocm_libfits
226 */
227bool operator<(LiteralKeyword const&, LiteralKeyword const&) noexcept;
228
229/**
230 * Compares equally if keyword record in @a lhs is the same as @a rhs (char for char).
231 *
232 * @relatesalso LiteralKeyword
233 * @ingroup daq_ocm_libfits
234 */
235bool operator==(LiteralKeyword const& lhs, LiteralKeyword const& rhs) noexcept;
236
237/**
238 * Compares inequally if keyword record in @a lhs is not the same as @a rhs (char for char).
239 *
240 * @relatesalso LiteralKeyword
241 * @ingroup daq_ocm_libfits
242 */
243bool operator!=(LiteralKeyword const&, LiteralKeyword const&) noexcept;
244
245std::ostream& operator<<(std::ostream& os, LiteralKeyword const& kw);
246
247/**
248 * Non template base class that is purely used to avoid type-deduction issues of ValueType.
249 */
251 // Possible value types that can be carried in a keyword
252 using ValueType = std::variant<std::string, std::int64_t, std::uint64_t, double, bool>;
253};
254
255/**
256 * A type safe version of LiteralKeyword that consist of the three basic components of a FITS
257 * keyword keyword record: name, value and optional comment.
258 *
259 * @note name should be used for the logical keyword name, not the keyword name according to FITS
260 * standard. E.g. the ESO hiearchical keywords all have the keyword name HIERARCH according to the
261 * standard, but this structure should instead use the logical fields where e.g. "HIERARCH ESO DPR
262 * CATG" is the logical keyword name.
263 *
264 * It does not model any specific unit, only the value type. Therefore it is not strictly necessary
265 * to have all possible types represented in ValueType (e.g. both singel and double precision
266 * floats).
267 *
268 * The idea is that the unit, formatting and ranges is provided provided by dictionaries.
269 *
270 * It also typically requires a dictionary to be able to understand how to parse @c value.
271 *
272 * @ingroup daq_ocm_libfits
273 */
274template <class Trait>
276 BasicKeyword() = default;
277 BasicKeyword(BasicKeyword const&) = default;
278 BasicKeyword(BasicKeyword&&) noexcept = default;
279 BasicKeyword(std::string name,
280 char const* string_value,
281 std::optional<std::string> comment = std::nullopt);
282 BasicKeyword(std::string name,
284 std::optional<std::string> comment = std::nullopt);
285
286 BasicKeyword& operator=(BasicKeyword&& rhs) noexcept = default;
287 BasicKeyword& operator=(BasicKeyword const& rhs) = default;
288
289 /**
290 * Query logical keyword name.
291 *
292 * @returns logical keyword name.
293 */
294 constexpr KeywordNameView GetName() const& noexcept {
295 return KeywordNameView{name, Trait::GetKeywordType()};
296 }
298
299 /**
300 * Compares all members for equality.
301 */
302 bool operator==(BasicKeyword const& rhs) const noexcept;
303 /**
304 * Compares all members for inequality.
305 */
306 bool operator!=(BasicKeyword const& rhs) const noexcept;
307 /**
308 * Uses @a name property as the sorting index.
309 */
310 bool operator<(BasicKeyword const& rhs) const noexcept;
311
312 /**
313 * Trimmed keyword name
314 */
315 std::string name;
317 /**
318 * Trimmed keyword comment
319 */
320 std::optional<std::string> comment;
321};
322
324 static constexpr KeywordType GetKeywordType() noexcept {
325 return KeywordType::Value;
326 }
327};
329 static constexpr KeywordType GetKeywordType() noexcept {
330 return KeywordType::Eso;
331 }
332};
333
334/**
335 * Standard FITS value keyword.
336 *
337 * @ingroup daq_ocm_libfits
338 */
340
341/**
342 * ESO hiearchical keyword.
343 *
344 * @ingroup daq_ocm_libfits
345 */
347
348/**
349 * Keyword sorting function.
350 *
351 * @relatesalso ValueKeyword
352 * @relatesalso EsoKeyword
353 * @ingroup daq_ocm_libfits
354 */
355bool operator<(LiteralKeyword const&, EsoKeyword const&) noexcept;
356/**
357 * Keyword sorting function.
358 *
359 * @relatesalso ValueKeyword
360 * @relatesalso LiteralKeyword
361 * @ingroup daq_ocm_libfits
362 */
363bool operator<(LiteralKeyword const&, ValueKeyword const&) noexcept;
364/**
365 * Keyword sorting function.
366 *
367 * @relatesalso ValueKeyword
368 * @relatesalso EsoKeyword
369 * @ingroup daq_ocm_libfits
370 */
371bool operator<(ValueKeyword const&, EsoKeyword const&) noexcept;
372/**
373 * Keyword sorting function.
374 *
375 * @relatesalso ValueKeyword
376 * @relatesalso LiteralKeyword
377 * @ingroup daq_ocm_libfits
378 */
379bool operator<(ValueKeyword const&, LiteralKeyword const&) noexcept;
380
381/**
382 * Keyword sorting function.
383 *
384 * @relatesalso ValueKeyword
385 * @relatesalso EsoKeyword
386 * @ingroup daq_ocm_libfits
387 */
388bool operator<(EsoKeyword const&, ValueKeyword const&) noexcept;
389/**
390 * Keyword sorting function.
391 *
392 * @relatesalso LiteralKeyword
393 * @relatesalso EsoKeyword
394 * @ingroup daq_ocm_libfits
395 */
396bool operator<(EsoKeyword const&, LiteralKeyword const&) noexcept;
397
398template <class Trait>
399std::ostream& operator<<(std::ostream& os, BasicKeyword<Trait> const& kw);
400
401template <class Trait>
402std::ostream& operator<<(std::ostream& os, BasicKeywordBase::ValueType const& kw);
403
404/**
405 * The different variants of keywords that are supported.
406 *
407 * @ingroup daq_ocm_libfits
408 */
409using KeywordVariant = std::variant<ValueKeyword, EsoKeyword, LiteralKeyword>;
410
411/**
412 * Subset of value-typed keywords.
413 *
414 * @ingroup daq_ocm_libfits
415 */
416using TypedKeywordVariant = std::variant<ValueKeyword, EsoKeyword>;
417
418/**
419 * Vector of keywords.
420 *
421 * @ingroup daq_ocm_libfits
422 */
423using KeywordVector = std::vector<KeywordVariant>;
424
425/**
426 * Ostream formatting of keywords.
427 *
428 * @ingroup daq_ocm_libfits
429 */
430std::ostream& operator<<(std::ostream& os, KeywordVariant const& kw);
431
432/**
433 * Get keyword name from @a keyword.
434 * @param keyword Keyword to query.
435 */
436constexpr KeywordNameView GetKeywordName(EsoKeyword const& keyword) noexcept {
437 return keyword.GetName();
438}
439
440constexpr KeywordNameView GetKeywordName(ValueKeyword const& keyword) noexcept {
441 return keyword.GetName();
442}
443
444/**
445 * Get keyword name from @a keyword variant.
446 * @param keyword Keyword to query.
447 */
448constexpr KeywordNameView GetKeywordName(KeywordVariant const& keyword) noexcept {
449 return std::visit([&](auto const& kw) { return kw.GetName(); }, keyword);
450}
451
452/**
453 * Get keyword class
454 * @param name Keyword name.
455 * @return keyword class.
456 */
457KeywordClass GetKeywordClass(std::string_view name);
458
459/**
460 * Compare logical keyword names of keyword of the same type.
461 *
462 * Comparing names only is useful to e.g. look up keyword by name, to modify it.
463 *
464 * @param lhs value to compare
465 * @param rhs value to compare
466 * @returns true iff lhs and rhs are the same type and their name property compares equal.
467 *
468 * @ingroup daq_ocm_libfits
469 */
470bool NameEquals(KeywordVariant const& lhs, KeywordVariant const& rhs) noexcept;
471
472enum class ConflictPolicy {
473 /**
474 * Replace keyword that conflicts.
475 */
476 Replace,
477 /**
478 * Skip keyword that conflicts.
479 */
480 Skip
481};
482
483/**
484 * Updates @a to with keywords from @a from.
485 *
486 * New keywords are inserted at the end. Existing keywords will be updated with new value if
487 * keyword type and name is the same.
488 *
489 * @param to Keywords to update to.
490 * @param from Keywords to update from.
491 * @param policy Determines what to do for a keyword conflict.
492 *
493 * @ingroup daq_ocm_libfits
494 */
496 KeywordVector const& from,
498
499/**
500 * Insert keywords
501 *
502 * Conflicting keywords are deleted from the current position.
503 *
504 * @param position Insert position that must lie within range (to_first, to_last]
505 * @param to_first Start of range to consider when deleting duplicate keywords.
506 * @param to_last End of range to consider when deleting duplicate keywords.
507 * @param from_first Range to insert from.
508 * @param from_last Range to insert from.
509 * @param from Keywords to update from.
510 *
511 * @ingroup daq_ocm_libfits
512 */
513void InsertKeywords(KeywordVector& keywords,
514 KeywordVector::iterator position,
515 KeywordVector::const_iterator from_first,
516 KeywordVector::const_iterator from_last);
517
518/**
519 * @name Format keyword using default formatting rules.
520 *
521 * @param keyword Keyword to format.
522 * @throw std::invalid_argument on failure.
523 */
524/// @{
525LiteralKeyword Format(KeywordVariant const& keyword);
526LiteralKeyword Format(ValueKeyword const& keyword);
527LiteralKeyword Format(EsoKeyword const& keyword);
529/// @}
530
531/**
532 * Indicates keyword is invalid for some reason.
533 */
534class InvalidKeyword : public std::invalid_argument {
535public:
536 InvalidKeyword(std::string_view name, char const* reason);
537 InvalidKeyword(std::string_view name, std::string const& reason);
538};
539
540/**
541 * Indicates keyword is unknown and cannot be formatted.
542 */
544public:
545 UnknownKeyword(std::string_view kw, std::vector<std::string> const& dictionaries);
546};
547
548/**
549 * Formats keyword against e.g. dictionaries.
550 */
552public:
553 virtual ~KeywordFormatter() noexcept;
554
555 /**
556 * Formats keyword.
557 *
558 * @throws UnknownKeyword if @a keyword is not known.
559 * @throws std::exception on other failures.
560 */
561 virtual auto Format(KeywordVariant const& keyword) const -> LiteralKeyword = 0;
562};
563
564/**
565 * Formats according to built-in rules without any dictionaries.
566 */
568public:
569 auto Format(KeywordVariant const& keyword) const -> LiteralKeyword override;
570};
571
572/**
573 * Format keyword value using built-in rules such that it can be used as a component when formatting
574 * a complete keyword record.
575 *
576 * @param name Keyword name, used to determine special handling of e.g. the `XTENSION` keyword.
577 * @param value Value to format.
578 * @return Formatted value. Strings are escaped.
579 */
580auto FormatFitsValue(KeywordNameView name, BasicKeywordBase::ValueType const& value) -> std::string;
581
582/**
583 * Untyped formatting where value already has been formatted *correctly*. No validation of value is
584 * made.
585 *
586 * @param name Logical keyword name & type.
587 * @param value formatted FITS keyword value.
588 * @param comment Comment which may be empty.
589 * @return formatted keyword record.
590 */
591auto UntypedFormat(KeywordNameView name, std::string_view value, std::string_view comment)
593
594/**
595 * Versioned namespace of sorting functions in case standard evolves but instruments want to freeze.
596 */
597namespace v1 {
598
599/**
600 * Sorting function object
601 *
602 * @ingroup daq_ocm_libfits
603 */
605 bool operator()(LiteralKeyword const&, LiteralKeyword const&) noexcept;
606};
607
608/**
609 * Sorts keywords according to ESO DICD standards.
610 *
611 * Specifically the following sorting order is applied:
612 *
613 * 1. Value keywords
614 * note: value keywords are not sorted with other value keywords to keep their relative order
615 * from the source they originally come from.
616 * 2. ESO keywords are sorted by
617 * 1. category (DPR, OBS, TPL, GEN, TEL, ADA, INS, DET)
618 * 2. keyword name
619 * 3. Commentary keywords (using only the keyword name)
620 *
621 * @param[in, out] keywords Vector of keywords to sort.
622 *
623 * @ingroup daq_ocm_libfits
624 */
625void StandardSort(std::vector<LiteralKeyword>& keywords);
626
627} // namespace v1
628} // namespace daq::fits
629
630#endif // #ifndef DAQ_OCM_DAQ_KEYWORD_HPP_
Indicates keyword is invalid for some reason.
Definition: keyword.hpp:534
Formats keyword against e.g.
Definition: keyword.hpp:551
virtual auto Format(KeywordVariant const &keyword) const -> LiteralKeyword=0
Formats keyword.
virtual ~KeywordFormatter() noexcept
Definition: keyword.cpp:809
Represents the literal 80-character FITS keyword record.
Definition: keyword.hpp:129
std::string_view comment
Comment may be empty.
Definition: keyword.hpp:142
constexpr Components GetComponents() const &noexcept
Get components of the keyword in its literal form with insignifant whitespaces removed.
Definition: keyword.hpp:206
constexpr KeywordType GetType() const noexcept
Definition: keyword.hpp:174
std::string_view GetRecord() const &noexcept
Definition: keyword.cpp:532
KeywordNameView GetName() &&noexcept=delete
constexpr KeywordNameView GetName() const &noexcept
Query logical keyword name.
Definition: keyword.hpp:190
LiteralKeyword() noexcept
Initializes an empty record (filled with ' ' characters)
Definition: keyword.cpp:480
Decomposed components a literal keyword.
Definition: keyword.hpp:134
Formats according to built-in rules without any dictionaries.
Definition: keyword.hpp:567
auto Format(KeywordVariant const &keyword) const -> LiteralKeyword override
Formats keyword.
Definition: keyword.cpp:812
Indicates keyword is unknown and cannot be formatted.
Definition: keyword.hpp:543
void StandardSort(std::vector< LiteralKeyword > &keywords)
Sorts keywords according to ESO DICD standards.
Definition: keyword.cpp:909
constexpr KeywordNameView GetKeywordName(EsoKeyword const &keyword) noexcept
Get keyword name from keyword.
Definition: keyword.hpp:436
void InsertKeywords(KeywordVector &keywords, KeywordVector::iterator position, KeywordVector::const_iterator from_first, KeywordVector::const_iterator from_last)
Insert keywords.
Definition: keyword.cpp:695
KeywordType
Type of FITS keyword.
Definition: keyword.hpp:68
@ Eso
An ESO hiearchical keyword.
Definition: keyword.hpp:76
@ Commentary
A commentary keyword, which are keywords that do not fall into the previous categories.
Definition: keyword.hpp:80
@ Value
A value keyword.
Definition: keyword.hpp:72
bool NameEquals(KeywordVariant const &lhs, KeywordVariant const &rhs) noexcept
Compare logical keyword names of keyword of the same type.
Definition: keyword.cpp:606
bool operator==(KeywordNameView lhs, KeywordNameView rhs) noexcept
Definition: keyword.cpp:472
LiteralKeyword Format(KeywordVariant const &keyword)
Definition: keyword.cpp:782
bool operator<(LiteralKeyword const &, LiteralKeyword const &) noexcept
Sort by logical keyword name (not DICD sort)
Definition: keyword.cpp:537
std::variant< ValueKeyword, EsoKeyword > TypedKeywordVariant
Subset of value-typed keywords.
Definition: keyword.hpp:416
KeywordClass GetKeywordClass(std::string_view name)
Get keyword class.
Definition: keyword.cpp:615
auto FormatFitsValue(KeywordNameView name, BasicKeywordBase::ValueType const &value) -> std::string
Format keyword value using built-in rules such that it can be used as a component when formatting a c...
Definition: keyword.cpp:717
auto UntypedFormat(KeywordNameView name, std::string_view value, std::string_view comment) -> LiteralKeyword
Untyped formatting where value already has been formatted correctly.
Definition: keyword.cpp:817
KeywordClass
Fits keyword type.
Definition: keyword.hpp:93
std::vector< KeywordVariant > KeywordVector
Vector of keywords.
Definition: keyword.hpp:423
bool operator!=(KeywordNameView lhs, KeywordNameView rhs) noexcept
Definition: keyword.cpp:476
std::variant< ValueKeyword, EsoKeyword, LiteralKeyword > KeywordVariant
The different variants of keywords that are supported.
Definition: keyword.hpp:409
void UpdateKeywords(KeywordVector &to, KeywordVector const &from, ConflictPolicy policy=ConflictPolicy::Replace)
Updates to with keywords from from.
Definition: keyword.cpp:679
std::ostream & operator<<(std::ostream &os, HduType hdu_type)
Format HduType hdu_type to os.
Definition: cfitsio.cpp:56
@ Replace
Replace keyword that conflicts.
@ Skip
Skip keyword that conflicts.
Non template base class that is purely used to avoid type-deduction issues of ValueType.
Definition: keyword.hpp:250
std::variant< std::string, std::int64_t, std::uint64_t, double, bool > ValueType
Definition: keyword.hpp:252
A type safe version of LiteralKeyword that consist of the three basic components of a FITS keyword ke...
Definition: keyword.hpp:275
bool operator==(BasicKeyword const &rhs) const noexcept
Compares all members for equality.
Definition: keyword.cpp:592
bool operator!=(BasicKeyword const &rhs) const noexcept
Compares all members for inequality.
Definition: keyword.cpp:597
BasicKeyword(BasicKeyword const &)=default
bool operator<(BasicKeyword const &rhs) const noexcept
Uses name property as the sorting index.
Definition: keyword.cpp:602
KeywordNameView GetName() &&=delete
BasicKeyword(BasicKeyword &&) noexcept=default
std::string name
Trimmed keyword name.
Definition: keyword.hpp:315
std::optional< std::string > comment
Trimmed keyword comment.
Definition: keyword.hpp:320
constexpr KeywordNameView GetName() const &noexcept
Query logical keyword name.
Definition: keyword.hpp:294
static constexpr KeywordType GetKeywordType() noexcept
Definition: keyword.hpp:329
std::string_view name
Definition: keyword.hpp:84
static constexpr KeywordType GetKeywordType() noexcept
Definition: keyword.hpp:324
Sorting function object.
Definition: keyword.hpp:604
bool operator()(LiteralKeyword const &, LiteralKeyword const &) noexcept
Definition: keyword.cpp:866