dxFeed Graal CXX API v4.2.0
Loading...
Searching...
No Matches
Common.hpp
1// Copyright (c) 2025 Devexperts LLC.
2// SPDX-License-Identifier: MPL-2.0
3
4#pragma once
5
6#include "Conf.hpp"
7
8#include "utils/StringUtils.hpp"
9
11
12#ifdef __cpp_lib_bit_cast
13# include <bit>
14#endif
15#include <climits>
16#include <cstring>
17
18#include <charconv>
19#include <chrono>
20#include <cmath>
21#include <string>
22#include <type_traits>
23#include <utility>
24#include <variant>
25
26#include "utils/debug/Debug.hpp"
27
29
30template <typename T>
31concept Integral = std::is_integral_v<T>;
32
33template <typename T>
34concept EnumConcept = std::is_enum_v<T>;
35
36template <class From, class To>
37concept ConvertibleTo = std::is_convertible_v<From, To> && requires { static_cast<To>(std::declval<From>()); };
38
39template <class T, class U>
40concept Derived = std::is_base_of_v<U, T>;
41
42template <class T, class U>
43concept Extends = Derived<T, U>;
44
45template <class T, class U>
46concept BaseOf = Derived<U, T>;
47
48namespace detail {
49template <typename T>
50struct RemoveAllPointers
51 : std::conditional_t<std::is_pointer_v<T>, RemoveAllPointers<std::remove_pointer_t<T>>, std::type_identity<T>> {};
52} // namespace detail
53
54template <typename T> using RemoveAllPointers = typename detail::RemoveAllPointers<T>::type;
55
56template <class... Ts> struct Overloads : Ts... {
57 using Ts::operator()...;
58};
59
60template <class... Ts> Overloads(Ts...) -> Overloads<Ts...>;
61
62struct DXFeedEventListener {};
63
64struct DXEndpointStateChangeListener {};
65
66struct IpfPropertyChangeListener {};
67
68struct InstrumentProfileUpdateListener {};
69
70template <typename... T> constexpr void ignoreUnused(const T &...) {
71}
72
73constexpr inline auto is_constant_evaluated(bool default_value = false) noexcept -> bool {
74#ifdef __cpp_lib_is_constant_evaluated
75 ignoreUnused(default_value);
76 return std::is_constant_evaluated();
77#else
78 return default_value;
79#endif
80}
81
82// Implementation of std::bit_cast for pre-C++20.
83template <typename To, typename From>
84constexpr To bit_cast(const From &from)
85#if __cpp_concepts
86 requires(sizeof(To) == sizeof(From))
87#endif
88{
89#ifdef __cpp_lib_bit_cast
90 if (is_constant_evaluated())
91 return std::bit_cast<To>(from);
92#endif
93 auto to = To();
94 // The cast suppresses a bogus -Wclass-memaccess on GCC.
95 std::memcpy(static_cast<void *>(&to), &from, sizeof(to));
96 return to;
97}
98
99/// Lightweight implementation of "nullable bool"
100enum class Tristate : std::uint8_t {
101 FALSE = 0,
102 TRUE = 1,
103 NONE = 2,
104};
105
106template <typename GraalList, typename ElementWrapper> struct GraalListUtils {
107 static std::ptrdiff_t calculateSize(std::ptrdiff_t initSize) noexcept {
108 using ListType = GraalList;
109 using SizeType = decltype(ListType::size);
110
111 if (initSize < 0) {
112 return 0;
113 }
114
115 if (initSize > std::numeric_limits<SizeType>::max()) {
116 return std::numeric_limits<SizeType>::max();
117 }
118
119 return initSize;
120 }
121
122 static void *newList(std::ptrdiff_t size) {
123 using ListType = GraalList;
124 using SizeType = decltype(ListType::size);
125 using ElementType = std::remove_pointer_t<decltype(ListType::elements)>;
126
127 auto *list = new ListType{static_cast<SizeType>(size), nullptr};
128
129 if (size == 0) {
130 return static_cast<void *>(list);
131 }
132
133 list->elements = new ElementType[size]{nullptr};
134
135 return list;
136 }
137
138 static bool setElement(void *graalList, std::ptrdiff_t elementIdx, void *element) noexcept {
139 using ListType = GraalList;
140 using SizeType = decltype(ListType::size);
141 using ElementType = std::remove_pointer_t<decltype(ListType::elements)>;
142
143 if (graalList == nullptr || elementIdx < 0 || elementIdx >= std::numeric_limits<SizeType>::max() ||
144 element == nullptr) {
145 return false;
146 }
147
148 static_cast<ListType *>(graalList)->elements[elementIdx] = static_cast<ElementType>(element);
149
150 return true;
151 }
152
153 static bool freeElements(void *graalList, std::ptrdiff_t count) {
154 using ListType = GraalList;
155 using SizeType = decltype(ListType::size);
156
157 if (graalList == nullptr || count < 0 || count >= std::numeric_limits<SizeType>::max()) {
158 return false;
159 }
160
161 auto *list = static_cast<ListType *>(graalList);
162
163 for (SizeType i = 0; i < count; i++) {
164 if (list->elements[i]) {
165 ElementWrapper::freeGraal(static_cast<void *>(list->elements[i]));
166 }
167 }
168
169 delete[] list->elements;
170 delete list;
171
172 return true;
173 }
174
175 static void freeList(void *graalList) {
176 using ListType = GraalList;
177 using SizeType = decltype(ListType::size);
178
179 if (graalList == nullptr) {
180 return;
181 }
182
183 auto list = static_cast<ListType *>(graalList);
184
185 if (list->size > 0 && list->elements != nullptr) {
186 for (SizeType elementIndex = 0; elementIndex < list->size; elementIndex++) {
187 if (list->elements[elementIndex]) {
188 ElementWrapper::freeGraal(static_cast<void *>(list->elements[elementIndex]));
189 }
190 }
191
192 delete[] list->elements;
193 }
194
195 delete list;
196 }
197
198 static std::vector<ElementWrapper> fromList(void *graalList) {
199 using ListType = GraalList;
200 using SizeType = decltype(ListType::size);
201
202 if (!graalList) {
203 return {};
204 }
205
206 std::vector<ElementWrapper> result{};
207
208 auto list = static_cast<ListType *>(graalList);
209
210 if (list->size > 0 && list->elements != nullptr) {
211 for (SizeType elementIndex = 0; elementIndex < list->size; elementIndex++) {
212 if (list->elements[elementIndex]) {
213 result.emplace_back(ElementWrapper::fromGraal(static_cast<void *>(list->elements[elementIndex])));
214 }
215 }
216 }
217
218 return result;
219 }
220};
221
222/**
223 * @return The number of milliseconds that have passed since the start of the Unix epoch (1970-01-01).
224 */
225inline auto now() {
226 return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
227 .count();
228}
229
230namespace math {
231static constexpr std::int64_t floorDiv(std::int64_t x, std::int64_t y) {
232 std::int64_t r = x / y;
233
234 // if the signs are different and modulo not zero, round down
235 if ((x < 0) != (y < 0) && (r * y != x)) {
236 r--;
237 }
238
239 return r;
240}
241
242static constexpr std::int64_t floorMod(std::int64_t x, std::int64_t y) {
243 return x - (floorDiv(x, y) * y);
244}
245
246static const double NaN = std::numeric_limits<double>::quiet_NaN();
247
248static bool equals(double a, double b, double eps = std::numeric_limits<double>::epsilon()) {
249 if (std::isnan(a) || std::isnan(b)) {
250 return false;
251 }
252
253 return std::abs(a - b) < eps;
254}
255
256template <typename T, typename U> static bool equals(T a, U b, double eps = std::numeric_limits<double>::epsilon()) {
257 if (std::isnan(static_cast<double>(a)) || std::isnan(static_cast<double>(b))) {
258 return false;
259 }
260
261 return std::abs(static_cast<double>(a) - static_cast<double>(b)) < eps;
262}
263
264} // namespace math
265
266namespace time_nanos_util {
267static constexpr std::int64_t NANOS_IN_MILLIS = 1'000'000LL;
268
269/**
270 * Returns time measured in nanoseconds since epoch from the time in milliseconds and its nano part.
271 * The result of this method is `timeMillis * 1'000'000 + timeNanoPart`.
272 *
273 * @param timeMillis time in milliseconds since epoch.
274 * @param timeNanoPart nanoseconds part that shall lie within [0..999999] interval.
275 * @return time measured in nanoseconds since epoch.
276 */
277static constexpr std::int64_t getNanosFromMillisAndNanoPart(std::int64_t timeMillis, std::int32_t timeNanoPart) {
278 return (timeMillis * NANOS_IN_MILLIS) + timeNanoPart;
279}
280
281/**
282 * Returns time measured in milliseconds since Java epoch from the time in nanoseconds.
283 * Idea is that nano part of time shall be within [0..999999] interval
284 * so that the following equation always holds
285 * `getMillisFromNanos(timeNanos) * 1'000'000 + getNanoPartFromNanos(timeNanos) == timeNanos`.
286 *
287 * @param timeNanos time measured in nanoseconds since epoch
288 * @return time measured in milliseconds since epoch.
289 * @see ::getNanoPartFromNanos()
290 */
291static constexpr std::int64_t getMillisFromNanos(std::int64_t timeNanos) {
292 return math::floorDiv(timeNanos, NANOS_IN_MILLIS);
293}
294
295/**
296 * Returns nano part of time.
297 * Idea is that nano part of time shall be within [0..999999] interval
298 * so that the following equation always holds
299 * `getMillisFromNanos(timeNanos) * 1'000'000 + getNanoPartFromNanos(timeNanos) == timeNanos`.
300 *
301 * @param timeNanos time measured in nanoseconds since epoch
302 * @return time measured in milliseconds since epoch.
303 * @see ::getMillisFromNanos()
304 */
305static constexpr std::int32_t getNanoPartFromNanos(std::int64_t timeNanos) {
306 return static_cast<std::int32_t>(math::floorMod(timeNanos, NANOS_IN_MILLIS));
307}
308
309} // namespace time_nanos_util
310
311namespace time_util {
312/// Number of milliseconds in a second.
313static constexpr std::int64_t SECOND = 1000LL;
314
315/// Number of milliseconds in a minute.
316static constexpr std::int64_t MINUTE = 60LL * SECOND;
317
318/// Number of milliseconds in an hour.
319static constexpr std::int64_t HOUR = 60LL * MINUTE;
320
321/// Number of milliseconds in an day.
322static constexpr std::int64_t DAY = 24LL * HOUR;
323
324/**
325 * Returns correct number of milliseconds with proper handling negative values.
326 * Idea is that number of milliseconds shall be within [0..999] interval
327 *
328 * @param timeMillis The timestamp in milliseconds
329 * @return a correct number of milliseconds
330 */
331static constexpr std::int32_t getMillisFromTime(std::int64_t timeMillis) {
332 return static_cast<std::int32_t>(math::floorMod(timeMillis, SECOND));
333}
334
335/**
336 * Returns correct number of seconds with proper handling negative values and overflows.
337 * Idea is that number of milliseconds shall be within [0..999] interval
338 *
339 * @param timeMillis The timestamp in milliseconds
340 * @return a correct number of second
341 */
342static constexpr std::int32_t getSecondsFromTime(std::int64_t timeMillis) {
343 if (timeMillis >= 0) {
344 return static_cast<std::int32_t>(
345 std::min(timeMillis / SECOND, static_cast<std::int64_t>(std::numeric_limits<std::int32_t>::max())));
346 }
347
348 return static_cast<std::int32_t>(
349 std::max((timeMillis + 1) / SECOND - 1, static_cast<std::int64_t>(std::numeric_limits<std::int32_t>::min())));
350}
351} // namespace time_util
352
353namespace math_util {
354
355/**
356 * Returns quotient according to number theory - i.e. when remainder is zero or positive.
357 *
358 * @tparam T The dividend's and divisor's type
359 * @param a dividend
360 * @param b divisor
361 * @return quotient according to number theory
362 */
363template <Integral T> constexpr static T div(T a, T b) {
364 if (a >= 0) {
365 return a / b;
366 }
367
368 if (b >= 0) {
369 return ((a + 1) / b) - 1;
370 }
371
372 return ((a + 1) / b) + 1;
373}
374
375template <Integral T> constexpr static T abs(T a) {
376 return a < 0 ? -a : a;
377}
378
379} // namespace math_util
380
381namespace day_util {
382
383DXFCXX_DISABLE_GCC_WARNINGS_PUSH("-Wunused-variable")
384static std::int32_t DAY_OF_YEAR[] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
386
387/**
388 * Returns yyyymmdd integer in Gregorian calendar for a specified day identifier.
389 * The day identifier is defined as the number of days since Unix epoch of January 1, 1970.
390 * The result is equal to `yearSign * (abs(year) * 10000 + month * 100 + day)`, where year,
391 * month, and day are in Gregorian calendar, month is between 1 and 12 inclusive, and day is counted from 1.
392 *
393 * @param dayId The day id
394 * @return integer date
395 */
396constexpr static std::int32_t getYearMonthDayByDayId(std::int32_t dayId) {
397 std::int32_t j = dayId + 2472632; // this shifts the epoch back to astronomical year -4800
398 std::int32_t g = math_util::div(j, 146097);
399 std::int32_t dg = j - g * 146097;
400 std::int32_t c = (dg / 36524 + 1) * 3 / 4;
401 std::int32_t dc = dg - c * 36524;
402 std::int32_t b = dc / 1461;
403 std::int32_t db = dc - b * 1461;
404 std::int32_t a = (db / 365 + 1) * 3 / 4;
405 std::int32_t da = db - a * 365;
406 std::int32_t y = g * 400 + c * 100 + b * 4 +
407 a; // this is the integer number of full years elapsed since March 1, 4801 BC at 00:00 UTC
408 std::int32_t m = (da * 5 + 308) / 153 -
409 2; // this is the integer number of full months elapsed since the last March 1 at 00:00 UTC
410 std::int32_t d =
411 da - (m + 4) * 153 / 5 + 122; // this is the number of days elapsed since day 1 of the month at 00:00 UTC
412 std::int32_t yyyy = y - 4800 + (m + 2) / 12;
413 std::int32_t mm = (m + 2) % 12 + 1;
414 std::int32_t dd = d + 1;
415 std::int32_t yyyymmdd = math_util::abs(yyyy) * 10000 + mm * 100 + dd;
416
417 return yyyy >= 0 ? yyyymmdd : -yyyymmdd;
418}
419
420std::int32_t getDayIdByYearMonthDay(std::int32_t year, std::int32_t month, std::int32_t day);
421
422} // namespace day_util
423
424namespace detail {
425template <typename...> struct MaxImpl;
426
427template <typename T> struct MaxImpl<T> {
428 using Type = T;
429};
430
431template <typename T, typename U> struct MaxImpl<T, U> {
432 using Type = std::conditional_t<sizeof(T) >= sizeof(U), T, U>;
433};
434
435template <typename T, typename U, typename V, typename... Ws> struct MaxImpl<T, U, V, Ws...> {
436 using Type = typename MaxImpl<T, typename MaxImpl<U, typename MaxImpl<V, Ws...>::Type>::Type>::Type;
437};
438} // namespace detail
439
440/**
441 * Returns max type by size (first is better)
442 */
443template <typename... Ts> using Max = typename detail::MaxImpl<Ts...>::Type;
444
445/**
446 * Performs a right arithmetic bit shift operation (>> in Java, C, etc). The sign bit is extended to preserve the
447 * signedness of the number.
448 *
449 * The result of the shift will be of the same type as the `value` being shifted.
450 * If the shift is a negative number of bits, then a @ref ::sal() "left arithmetic shift" will be performed.
451 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then if the `value` is
452 * negative (signed integer type), `-1` will be returned, and if positive, then `0` will be returned.
453 *
454 * @tparam V The type of `value`
455 * @tparam S The type of `shift`
456 * @param value The value to be shifted.
457 * @param shift The shift in bits
458 * @return The shifted `value`
459 */
460template <Integral V, Integral S> static constexpr V sar(V value, S shift) noexcept;
461
462/**
463 * Performs a left arithmetic bit shift operation (<< in Java, C, etc).
464 *
465 * The result of the shift will be of the same type as the `value` being shifted.
466 * If the shift is a negative number of bits, then a @ref ::sar() "right arithmetic shift" will be performed.
467 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
468 * returned.
469 *
470 * @tparam V The type of `value`
471 * @tparam S The type of `shift`
472 * @param value The value to be shifted
473 * @param shift The shift in bits
474 * @return The shifted `value`
475 */
476template <Integral V, Integral S> static constexpr V leftArithmeticShift(V value, S shift) noexcept {
477 if constexpr (std::is_signed_v<S>) {
478 if (shift < 0) {
479 return sar(value, -shift);
480 }
481 }
482
483 if (shift == 0 || value == 0) {
484 return value;
485 }
486
487 auto unsignedShift = static_cast<std::make_unsigned_t<S>>(shift);
488
489 if (unsignedShift >= sizeof(V) * CHAR_BIT) {
490 return 0;
491 }
492
493 return value << unsignedShift;
494}
495
496/**
497 * Performs a left arithmetic bit shift operation (<< in Java, C, etc).
498 *
499 * The result of the shift will be of the same type as the `value` being shifted.
500 * If the shift is a negative number of bits, then a @ref ::sar() "right arithmetic shift" will be performed.
501 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
502 * returned.
503 *
504 * @tparam V The type of `value`
505 * @tparam S The type of `shift`
506 * @param value The value to be shifted.
507 * @param shift The shift in bits
508 * @return The shifted `value`
509 */
510template <Integral V, Integral S> static constexpr V sal(V value, S shift) noexcept {
511 return leftArithmeticShift(value, shift);
512}
513
514/**
515 * Performs a right arithmetic bit shift operation (>> in Java, C, etc). The sign bit is extended to preserve the
516 * signedness of the number.
517 *
518 * The result of the shift will be of the same type as the `value` being shifted.
519 * If the shift is a negative number of bits, then a @ref ::sal() "left arithmetic shift" will be performed.
520 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then if the `value` is
521 * negative (signed integer type), `-1` will be returned, and if positive, then `0` will be returned.
522 *
523 * @tparam V The type of `value`
524 * @tparam S The type of `shift`
525 * @param value The value to be shifted
526 * @param shift The shift in bits
527 * @return The shifted `value`
528 */
529template <Integral V, Integral S> static constexpr V rightArithmeticShift(V value, S shift) noexcept {
530 if constexpr (std::is_signed_v<S>) {
531 if (shift < 0) {
532 return sal(value, -shift);
533 }
534 }
535
536 if (shift == 0 || value == 0) {
537 return value;
538 }
539
540 auto unsignedShift = static_cast<std::make_unsigned_t<S>>(shift);
541
542 if (unsignedShift >= sizeof(V) * CHAR_BIT) {
543 return value < 0 ? -1 : 0;
544 }
545
546 return value >> unsignedShift;
547}
548
549/**
550 * Performs a right arithmetic bit shift operation (>> in Java, C, etc). The sign bit is extended to preserve the
551 * signedness of the number.
552 *
553 * The result of the shift will be of the same type as the `value` being shifted.
554 * If the shift is a negative number of bits, then a @ref ::sal() "left arithmetic shift" will be performed.
555 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then if the `value` is
556 * negative (signed integer type), `-1` will be returned, and if positive, then `0` will be returned.
557 *
558 * @tparam V The type of `value`
559 * @tparam S The type of `shift`
560 * @param value The value to be shifted.
561 * @param shift The shift in bits
562 * @return The shifted `value`
563 */
564template <Integral V, Integral S> static constexpr V sar(V value, S shift) noexcept {
565 return rightArithmeticShift(value, shift);
566}
567
568/**
569 * Performs a right logical bit shift operation (>>> in Java). Fills the left bits by zero.
570 *
571 * The result of the shift will be of the same type as the `value` being shifted.
572 * If the shift is a negative number of bits, then a @ref ::shl() "left logical shift" will be performed.
573 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
574 * returned.
575 *
576 * @tparam V The type of `value`
577 * @tparam S The type of `shift`
578 * @param value The value to be shifted.
579 * @param shift The shift in bits
580 * @return The shifted `value`
581 */
582template <Integral V, Integral S> static constexpr V shr(V value, S shift) noexcept;
583
584/**
585 * Performs a left logical bit shift operation.
586 *
587 * The result of the shift will be of the same type as the `value` being shifted.
588 * If the shift is a negative number of bits, then a @ref ::shr() "right logical shift" will be performed.
589 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
590 * returned.
591 *
592 * @tparam V The type of `value`
593 * @tparam S The type of `shift`
594 * @param value The value to be shifted
595 * @param shift The shift in bits
596 * @return The shifted `value`
597 */
598template <Integral V, Integral S> static constexpr V leftLogicalShift(V value, S shift) noexcept {
599 if constexpr (std::is_signed_v<S>) {
600 if (shift < 0) {
601 return shr(value, -shift);
602 }
603 }
604
605 if (shift == 0 || value == 0) {
606 return value;
607 }
608
609 auto unsignedShift = static_cast<std::make_unsigned_t<S>>(shift);
610
611 if (unsignedShift >= sizeof(V) * CHAR_BIT) {
612 return 0;
613 }
614
615 return value << unsignedShift;
616}
617
618/**
619 * Performs a left logical bit shift operation.
620 *
621 * The result of the shift will be of the same type as the `value` being shifted.
622 * If the shift is a negative number of bits, then a @ref ::shr() "right logical shift" will be performed.
623 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
624 * returned.
625 *
626 * @tparam V The type of `value`
627 * @tparam S The type of `shift`
628 * @param value The value to be shifted.
629 * @param shift The shift in bits
630 * @return The shifted `value`
631 */
632template <Integral V, Integral S> static constexpr V shl(V value, S shift) noexcept {
633 return leftLogicalShift(value, shift);
634}
635
636/**
637 * Performs a right logical bit shift operation (>>> in Java). Fills the left bits by zero.
638 *
639 * The result of the shift will be of the same type as the `value` being shifted.
640 * If the shift is a negative number of bits, then a @ref ::shl() "left logical shift" will be performed.
641 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
642 * returned.
643 *
644 * @tparam V The type of `value`
645 * @tparam S The type of `shift`
646 * @param value The value to be shifted
647 * @param shift The shift in bits
648 * @return The shifted `value`
649 */
650template <Integral V, Integral S> static constexpr V rightLogicalShift(V value, S shift) noexcept {
651 if constexpr (std::is_signed_v<S>) {
652 if (shift < 0) {
653 return shl(value, -shift);
654 }
655 }
656
657 if (shift == 0 || value == 0) {
658 return value;
659 }
660
661 auto unsignedShift = static_cast<std::make_unsigned_t<S>>(shift);
662
663 if (unsignedShift >= sizeof(V) * CHAR_BIT) {
664 return 0;
665 }
666
667 return static_cast<V>(static_cast<std::make_unsigned_t<V>>(value) >> unsignedShift);
668}
669
670/**
671 * Performs a right logical bit shift operation (>>> in Java). Fills the left bits by zero.
672 *
673 * The result of the shift will be of the same type as the `value` being shifted.
674 * If the shift is a negative number of bits, then a @ref ::shl() "left logical shift" will be performed.
675 * If the shift size is greater than or equal to the number of bits in the shifted `value`, then `0` will be
676 * returned.
677 *
678 * @tparam V The type of `value`
679 * @tparam S The type of `shift`
680 * @param value The value to be shifted.
681 * @param shift The shift in bits
682 * @return The shifted `value`
683 */
684template <Integral V, Integral S> static constexpr V shr(V value, S shift) noexcept {
685 return rightLogicalShift(value, shift);
686}
687
688template <Integral A, Integral B> static constexpr A andOp(A a, B b) noexcept {
689 using Common = std::make_unsigned_t<Max<A, B>>;
690
691 return static_cast<A>(static_cast<Common>(a) & static_cast<Common>(b));
692}
693
694template <Integral A, Integral B> static constexpr A orOp(A a, B b) noexcept {
695 using Common = std::make_unsigned_t<Max<A, B>>;
696
697 return static_cast<A>(static_cast<Common>(a) | static_cast<Common>(b));
698}
699
700template <Integral A, Integral B> static constexpr A xorOp(A a, B b) noexcept {
701 using Common = std::make_unsigned_t<Max<A, B>>;
702
703 return static_cast<A>(static_cast<Common>(a) ^ static_cast<Common>(b));
704}
705
706template <Integral F, Integral M, Integral S> static constexpr F getBits(F flags, M mask, S shift) noexcept {
707 return static_cast<F>(andOp(shr(flags, shift), mask));
708}
709
710template <Integral T> static constexpr T setBits(T flags, T mask, T shift, T bits) noexcept {
711 if constexpr (std::is_signed_v<T>) {
712 using U = std::make_unsigned_t<T>;
713
714 return static_cast<T>((static_cast<U>(flags) & ~(static_cast<U>(mask) << static_cast<U>(shift))) |
715 ((static_cast<U>(bits) & static_cast<U>(mask)) << static_cast<U>(shift)));
716 } else {
717 return (flags & ~(mask << shift)) | ((bits & mask) << shift);
718 }
719}
720
721template <Integral F, Integral M, Integral S, Integral B>
722static constexpr F setBits(F flags, M mask, S shift, B bits) noexcept {
723 if constexpr (std::is_signed_v<F> || std::is_signed_v<M> || std::is_signed_v<S> || std::is_signed_v<B>) {
724 using U = std::make_unsigned_t<Max<F, M, S, B>>;
725
726 return static_cast<F>((static_cast<U>(flags) & ~(static_cast<U>(mask) << static_cast<U>(shift))) |
727 ((static_cast<U>(bits) & static_cast<U>(mask)) << static_cast<U>(shift)));
728 } else {
729 return (flags & ~(mask << shift)) | ((bits & mask) << shift);
730 }
731}
732
733template <std::size_t Bits> struct hashMixImpl;
734
735template <> struct hashMixImpl<64> {
736 constexpr static std::uint64_t fn(std::uint64_t x) noexcept {
737 std::uint64_t const m = (static_cast<std::uint64_t>(0xe9846af) << 32) + 0x9b1a615d;
738
739 x ^= x >> 32;
740 x *= m;
741 x ^= x >> 32;
742 x *= m;
743 x ^= x >> 28;
744
745 return x;
746 }
747};
748
749template <> struct hashMixImpl<32> {
750 constexpr static std::uint32_t fn(std::uint32_t x) noexcept {
751 std::uint32_t const m1 = 0x21f0aaad;
752 std::uint32_t const m2 = 0x735a2d97;
753
754 x ^= x >> 16;
755 x *= m1;
756 x ^= x >> 15;
757 x *= m2;
758 x ^= x >> 15;
759
760 return x;
761 }
762};
763
764constexpr static std::size_t hashMix(std::size_t v) noexcept {
765 return hashMixImpl<sizeof(std::size_t) * CHAR_BIT>::fn(v);
766}
767
768template <class T> constexpr void hashCombine(std::size_t &seed, const T &v) noexcept {
769 seed = hashMix(seed + 0x9e3779b9 + std::hash<T>()(v));
770}
771
772template <Integral T, Integral U> constexpr std::size_t pack(T t, U u) noexcept {
773 constexpr auto sizeOfSize = sizeof(std::size_t) * CHAR_BIT;
774
775 return orOp(shl(t, sizeOfSize / 2), u);
776}
777
778constexpr std::pair<std::size_t, std::size_t> unpack(std::size_t v) noexcept {
779 constexpr auto sizeOfSize = sizeof(std::size_t) * CHAR_BIT;
780
781 return {shr(v, sizeOfSize / 2), andOp(v, shr(~std::size_t{}, sizeOfSize / 2))};
782}
783
784template <typename T, typename U> T fitToType(const U &size) {
785 static_assert(sizeof(T) <= sizeof(U));
786
787 return static_cast<T>(static_cast<U>(std::numeric_limits<T>::max()) < size ? std::numeric_limits<T>::max() : size);
788}
789
790/**
791 * A simple wrapper around strings or something similar to strings to reduce the amount of code for methods that take
792 * strings as input.
793 */
796
797 private:
798 DataType data_{};
799
800 public:
801 StringLikeWrapper(std::string_view sv) : data_{sv} {
802 }
803
804 StringLikeWrapper(const char *chars) : data_{chars == nullptr ? std::string_view{} : std::string_view{chars}} {
805 }
806
807 StringLikeWrapper(const std::string &s) : data_{s} {
808 }
809
810 StringLikeWrapper(std::string &&s) : data_{std::move(s)} {
811 }
812
813 template <auto N>
814 StringLikeWrapper(const char (&chars)[N]) : StringLikeWrapper{std::string_view{chars, chars + N}} {
815 }
816
817 operator std::string() const {
818 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
819 return {sv->data(), sv->size()};
820 } else {
821 return std::get<std::string>(data_);
822 }
823 }
824
825 operator std::string_view() const & {
826 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
827 return *sv;
828 } else {
829 return std::get<std::string>(data_);
830 }
831 }
832
833 const char *data() const {
834 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
835 return sv->data();
836 } else {
837 return std::get<std::string>(data_).c_str();
838 }
839 }
840
841 const char *c_str() const {
842 return data();
843 }
844
845 bool empty() const {
846 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
847 return sv->empty();
848 } else {
849 return std::get<std::string>(data_).empty();
850 }
851 }
852
853 std::size_t size() const {
854 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
855 return sv->size();
856 } else {
857 return std::get<std::string>(data_).size();
858 }
859 }
860
861 std::size_t length() const {
862 return size();
863 }
864
865 bool ends_with(const StringLikeWrapper &sw) const {
866 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
867 return sv->ends_with(sw);
868 } else {
869 return std::get<std::string>(data_).ends_with(sw);
870 }
871 }
872
874 if (auto sv = std::get_if<std::string_view>(&data_); sv) {
875 auto sv2 = sv->substr(pos, count);
876
877 return {sv2.data(), sv2.size()};
878 } else {
879 return std::get<std::string>(data_).substr(pos, count);
880 }
881 }
882
883 bool operator==(const StringLikeWrapper &sw) const {
884 return sw.operator std::string_view() == this->operator std::string_view();
885 }
886
887 friend std::string operator+(const StringLikeWrapper &sw1, const StringLikeWrapper &sw2) {
888 return sw1.operator std::string() + sw2.operator std::string();
889 }
890
891 explicit operator double() const {
892 double result{};
893
894 // At the moment, clang\apple clang's std lib does not support a version of the `from_chars` function (needed
895 // for `std::string_view`) for the `double` type.
896#ifdef _LIBCPP_VERSION
897 auto s = this->operator std::string();
898
899 result = std::stod(s);
900#else
901 auto sw = this->operator std::string_view();
902
903 std::from_chars(sw.data(), sw.data() + sw.size(), result);
904#endif
905
906 return result;
907 }
908};
909
910/// Universal functional object that allows searching std::unordered_map for string-like keys.
912 using HashType = std::hash<std::string_view>;
913 using is_transparent = void;
914
915 std::size_t operator()(const char *str) const {
916 return HashType{}(str);
917 }
918
919 std::size_t operator()(std::string_view sw) const {
920 return HashType{}(sw);
921 }
922
923 std::size_t operator()(std::string const &str) const {
924 return HashType{}(str);
925 }
926
927 std::size_t operator()(const StringLikeWrapper &sw) const {
928 return HashType{}(sw);
929 }
930};
931
932namespace util {
933
934void throwInvalidChar(char c, const std::string &name);
935
936inline void checkChar(char c, std::uint32_t mask, const std::string &name) {
937 if ((andOp(c, ~mask)) != 0) {
938 throwInvalidChar(c, name);
939 }
940}
941
942} // namespace util
943
944namespace math {
945
946template <Integral Type, typename ResultType = int> ResultType compare(Type v1, Type v2) {
947 if (v1 < v2) {
948 return -1;
949 }
950
951 if (v2 < v1) {
952 return 1;
953 }
954
955 return 0;
956}
957
958inline int compare(double d1, double d2) {
959 if (std::isnan(d1) || std::isnan(d2)) {
960 return std::isnan(d1) ? (std::isnan(d2) ? 0 : -1) : 1;
961 }
962
963 if (d1 < d2) {
964 return -1;
965 }
966
967 if (d1 > d2) {
968 return 1;
969 }
970
971 return 0;
972}
973
974} // namespace math
975
977
#define DXFCXX_DISABLE_MSC_WARNINGS_POP()
Definition Conf.hpp:22
#define DXFCPP_END_NAMESPACE
Definition Conf.hpp:70
#define DXFCPP_BEGIN_NAMESPACE
Definition Conf.hpp:67
#define DXFCXX_DISABLE_GCC_WARNINGS_PUSH(warnings)
Definition Conf.hpp:38
#define DXFCXX_DISABLE_GCC_WARNINGS_POP()
Definition Conf.hpp:40
#define DXFCXX_DISABLE_MSC_WARNINGS_PUSH(warnings)
Definition Conf.hpp:21
#define DXFCPP_EXPORT
Definition api.h:35
Base abstract class for all dxFeed C++ API entities.
Definition Entity.hpp:13
Marks all event types that can be received via dxFeed API.
Definition EventType.hpp:31
A helper class needed to construct smart pointers to objects, and does not allow explicit constructio...
Definition SharedEntity.hpp:89
static auto createShared(Args &&...args)
Creates smart pointer to object.
Definition SharedEntity.hpp:103
Base abstract "shared entity" class. Has some helpers for dynamic polymorphism.
Definition SharedEntity.hpp:21
virtual std::string toString() const
Returns a string representation of the current object.
Definition SharedEntity.hpp:78
std::shared_ptr< T > sharedAs() const noexcept
Returns a pointer to the current object wrapped in a smart pointer to type T.
Definition SharedEntity.hpp:69
std::shared_ptr< T > sharedAs() noexcept
Returns a pointer to the current object wrapped in a smart pointer to type T.
Definition SharedEntity.hpp:56
bool is() const noexcept
Checks that pointer to the current type could be converted to type T* In other words: whether type T ...
Definition SharedEntity.hpp:35
Universal functional object that allows searching std::unordered_map for string-like keys.
Definition Common.hpp:911
A simple wrapper around strings or something similar to strings to reduce the amount of code for meth...
Definition Common.hpp:794