20#ifndef LIBREPCB_CORE_TOOLBOX_H
21#define LIBREPCB_CORE_TOOLBOX_H
26#include "../exceptions.h"
27#include "../types/angle.h"
28#include "../types/length.h"
29#include "../types/point.h"
31#include <optional/tl/optional.hpp>
78 static inline QSet<T>
toSet(
const QList<T>& list)
noexcept {
79#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
80 return QSet<T>(list.begin(), list.end());
86#if (QT_VERSION_MAJOR < 6)
100 static inline QSet<T>
toSet(
const QVector<T>& vector)
noexcept {
101#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
102 return QSet<T>(vector.begin(), vector.end());
104 return vector.toList().toSet();
121 template <
typename T>
122 static inline QVector<T>
toVector(
const QSet<T>& set)
noexcept {
123#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
124 return QVector<T>(set.begin(), set.end());
126 return set.toList().toVector();
142 template <
typename T>
143 static inline QList<T>
toList(
const QSet<T>& set)
noexcept {
144#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
145 return QList<T>(set.begin(), set.end());
151 template <
typename T>
153 QList<T> list = set.values();
154 std::sort(list.begin(), list.end());
158 template <
typename T,
typename Compare>
159 static QList<T>
sortedQSet(
const QSet<T>& set,
const Compare& cmp)
noexcept {
160 QList<T> list = set.values();
161 std::sort(list.begin(), list.end(), cmp);
165 template <
typename T>
166 static T
sorted(
const T& container)
noexcept {
168 std::sort(copy.begin(), copy.end());
182 template <
typename T,
typename Compare>
184 T& container, Compare compare,
185 Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive,
186 bool ignorePunctuation =
false) noexcept {
188 collator.setNumericMode(
true);
189 collator.setCaseSensitivity(caseSensitivity);
190 collator.setIgnorePunctuation(ignorePunctuation);
191 std::sort(container.begin(), container.end(),
192 [&collator, &compare](
const typename T::value_type& lhs,
193 const typename T::value_type& rhs) {
194 return compare(collator, lhs, rhs);
205 template <
typename T>
207 T& container, Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive,
208 bool ignorePunctuation =
false) noexcept {
211 [](
const QCollator& collator,
const typename T::value_type& lhs,
212 const typename T::value_type& rhs) {
return collator(lhs, rhs); },
213 caseSensitivity, ignorePunctuation);
231 return QRectF(-radius, -radius, 2 * radius, 2 * radius);
235 return QRectF(-rx, -ry, 2 * rx, 2 * ry);
239 qreal offset)
noexcept {
240 return rect.adjusted(-offset, -offset, offset, offset);
244 const QPainterPath& path,
const QPen& pen,
const QBrush& brush,
248 const
Angle& angle) noexcept;
250 const
Angle& angle) noexcept;
289 const
Point& l2) noexcept;
304 Point* nearest =
nullptr) noexcept;
356 const QRegularExpression& removeRegex,
357 bool trim = true,
bool toLower = false,
358 bool toUpper = false,
359 const QString& spaceReplacement = " ",
360 int maxLength = -1) noexcept;
383 template <typename T>
385 const QLocale& locale) noexcept {
386 QString s = locale.toString(value,
'f', decimals);
387 for (
int i = 1; (i < decimals) && s.endsWith(locale.zeroDigit()); ++i) {
390 if (qAbs(value) >= 1000) {
391 s.remove(locale.groupSeparator());
402 template <
typename T>
404 using UnsignedT =
typename std::make_unsigned<T>::type;
413 valueAbs = -
static_cast<UnsignedT
>(value);
415 valueAbs =
static_cast<UnsignedT
>(value);
418 QString str = QString::number(valueAbs);
419 if (str.length() > pointPos) {
421 str.insert(str.length() - pointPos,
'.');
423 for (qint32 i = pointPos - str.length(); i != 0; i--) str.insert(0,
'0');
427 while (str.endsWith(
'0') && !str.endsWith(
".0")) str.chop(1);
429 if (value < 0) str.insert(0,
'-');
441 template <
typename T>
443 using UnsignedT =
typename std::make_unsigned<T>::type;
445 const T min = std::numeric_limits<T>::min();
446 const T max = std::numeric_limits<T>::max();
447 const UnsignedT max_u = std::numeric_limits<UnsignedT>::max();
460 State state = State::START;
461 UnsignedT valueAbs = 0;
463 qint32 expOffset = pointPos;
465 const quint32 maxExp = std::numeric_limits<quint32>::max();
467 bool expSign =
false;
469 for (QChar c : str) {
470 if (state == State::INVALID) {
482 state = State::AFTER_SIGN;
483 }
else if (c ==
'+') {
484 state = State::AFTER_SIGN;
485 }
else if (c ==
'.') {
486 state = State::LONELY_DOT;
487 }
else if (c.isDigit()) {
488 valueAbs =
static_cast<UnsignedT
>(c.digitValue());
489 state = State::INT_PART;
491 state = State::INVALID;
495 case State::AFTER_SIGN:
497 state = State::LONELY_DOT;
498 }
else if (c.isDigit()) {
499 valueAbs =
static_cast<UnsignedT
>(c.digitValue());
500 state = State::INT_PART;
502 state = State::INVALID;
506 case State::LONELY_DOT:
508 valueAbs =
static_cast<UnsignedT
>(c.digitValue());
510 state = State::FRAC_PART;
512 state = State::INVALID;
516 case State::INT_PART:
518 state = State::FRAC_PART;
519 }
else if (c ==
'e' || c ==
'E') {
521 }
else if (c.isDigit()) {
522 UnsignedT digit =
static_cast<UnsignedT
>(c.digitValue());
523 if (valueAbs > (max_u / 10)) {
525 state = State::INVALID;
529 if (valueAbs > (max_u - digit)) {
531 state = State::INVALID;
536 state = State::INVALID;
540 case State::FRAC_PART:
541 if (c ==
'e' || c ==
'E') {
543 }
else if (c.isDigit()) {
544 UnsignedT digit =
static_cast<UnsignedT
>(c.digitValue());
545 if (valueAbs > (max_u / 10)) {
547 state = State::INVALID;
551 if (valueAbs > (max_u - digit)) {
553 state = State::INVALID;
559 state = State::INVALID;
566 state = State::EXP_AFTER_SIGN;
567 }
else if (c ==
'+') {
568 state = State::EXP_AFTER_SIGN;
569 }
else if (c.isDigit()) {
570 exp =
static_cast<quint32
>(c.digitValue());
571 state = State::EXP_DIGITS;
573 state = State::INVALID;
577 case State::EXP_AFTER_SIGN:
579 exp =
static_cast<quint32
>(c.digitValue());
580 state = State::EXP_DIGITS;
582 state = State::INVALID;
586 case State::EXP_DIGITS:
588 quint32 digit =
static_cast<quint32
>(c.digitValue());
589 if (exp > (maxExp / 10)) {
591 state = State::INVALID;
595 if (exp > (maxExp - digit)) {
597 state = State::INVALID;
602 state = State::INVALID;
611 case State::AFTER_SIGN:
612 case State::LONELY_DOT:
614 case State::EXP_AFTER_SIGN:
618 case State::INT_PART:
619 case State::FRAC_PART:
620 case State::EXP_DIGITS:
625 quint32 expOffsetAbs;
627 expOffsetAbs = -
static_cast<quint32
>(expOffset);
629 expOffsetAbs =
static_cast<quint32
>(expOffset);
632 if (expSign == (expOffset < 0)) {
633 if (exp > (maxExp - expOffsetAbs)) {
640 if (exp < expOffsetAbs) {
654 for (quint32 i = 0; i < exp; i++) {
655 if ((valueAbs % 10) != 0) {
663 for (quint32 i = 0; i < exp; i++) {
664 if (valueAbs > (max_u / 10)) {
674 if (valueAbs >
static_cast<UnsignedT
>(min)) {
677 result =
static_cast<T
>(-valueAbs);
680 if (valueAbs >
static_cast<UnsignedT
>(max)) {
683 result =
static_cast<T
>(valueAbs);
693 tr(
"Invalid fixed point number string: \"%1\"").arg(str));
703 const QString& input,
704 const QVector<std::tuple<int, int, QStringList>>& replacements)
noexcept;
The Angle class is used to represent an angle (for example 12.75 degrees)
Definition: angle.h:78
The Length class is used to represent a length (for example 12.75 millimeters)
Definition: length.h:83
The Point class is used to represent a point/coordinate/vector, for example (1.2mm; 5....
Definition: point.h:79
The RuntimeError class.
Definition: exceptions.h:218
Definition: occmodel.cpp:77
type_safe::constrained_type< Length, UnsignedLengthConstraint, UnsignedLengthVerifier > UnsignedLength
Definition: length.h:696