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"
78 static inline QSet<T>
toSet(
const QList<T>& list)
noexcept {
79 return QSet<T>(list.begin(), list.end());
95 static inline QVector<T>
toVector(
const QSet<T>& set)
noexcept {
96 return QVector<T>(set.begin(), set.end());
111 template <
typename T>
112 static inline QList<T>
toList(
const QSet<T>& set)
noexcept {
113 return QList<T>(set.begin(), set.end());
116 template <
typename T>
118 static_assert(!std::is_pointer<T>::value,
119 "Container holds pointers, sorting makes no sense.");
120 QList<T> list = set.values();
121 std::sort(list.begin(), list.end());
125 template <
typename T,
typename Compare>
126 static QList<T>
sortedQSet(
const QSet<T>& set,
const Compare& cmp)
noexcept {
127 QList<T> list = set.values();
128 std::sort(list.begin(), list.end(), cmp);
132 template <
typename T>
133 static T
sorted(
const T& container)
noexcept {
134 static_assert(!std::is_pointer<T>::value,
135 "Container holds pointers, sorting makes no sense.");
137 std::sort(copy.begin(), copy.end());
151 template <
typename T,
typename Compare>
153 T& container, Compare compare,
154 Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive,
155 bool ignorePunctuation =
false) noexcept {
157 collator.setNumericMode(
true);
158 collator.setCaseSensitivity(caseSensitivity);
159 collator.setIgnorePunctuation(ignorePunctuation);
160 std::sort(container.begin(), container.end(),
161 [&collator, &compare](
const typename T::value_type& lhs,
162 const typename T::value_type& rhs) {
163 return compare(collator, lhs, rhs);
174 template <
typename T>
176 T& container, Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive,
177 bool ignorePunctuation =
false) noexcept {
180 [](
const QCollator& collator,
const typename T::value_type& lhs,
181 const typename T::value_type& rhs) {
return collator(lhs, rhs); },
182 caseSensitivity, ignorePunctuation);
200 return QRectF(-radius, -radius, 2 * radius, 2 * radius);
204 return QRectF(-rx, -ry, 2 * rx, 2 * ry);
208 qreal offset)
noexcept {
209 return rect.adjusted(-offset, -offset, offset, offset);
213 const QPainterPath& path,
const QPen& pen,
const QBrush& brush,
217 const
Angle& angle) noexcept;
219 const
Angle& angle) noexcept;
247 const
Point& end) noexcept;
274 const
Point& l2) noexcept;
289 Point* nearest =
nullptr) noexcept;
341 const QRegularExpression& removeRegex,
342 bool trim = true,
bool toLower = false,
343 bool toUpper = false,
344 const QString& spaceReplacement = " ",
345 int maxLength = -1) noexcept;
368 template <typename T>
370 const QLocale& locale) noexcept {
371 QString s = locale.toString(value,
'f', decimals);
372 for (
int i = 1; (i < decimals) && s.endsWith(locale.zeroDigit()); ++i) {
375 if (qAbs(value) >= 1000) {
376 s.remove(locale.groupSeparator());
387 template <
typename T>
389 using UnsignedT =
typename std::make_unsigned<T>::type;
398 valueAbs = -
static_cast<UnsignedT
>(value);
400 valueAbs =
static_cast<UnsignedT
>(value);
403 QString str = QString::number(valueAbs);
404 if (str.length() > pointPos) {
406 str.insert(str.length() - pointPos,
'.');
408 for (qint32 i = pointPos - str.length(); i != 0; i--) str.insert(0,
'0');
412 while (str.endsWith(
'0') && !str.endsWith(
".0")) str.chop(1);
414 if (value < 0) str.insert(0,
'-');
426 template <
typename T>
428 using UnsignedT =
typename std::make_unsigned<T>::type;
430 const T min = std::numeric_limits<T>::min();
431 const T max = std::numeric_limits<T>::max();
432 const UnsignedT max_u = std::numeric_limits<UnsignedT>::max();
445 State state = State::START;
446 UnsignedT valueAbs = 0;
448 qint32 expOffset = pointPos;
450 const quint32 maxExp = std::numeric_limits<quint32>::max();
452 bool expSign =
false;
454 for (QChar c : str) {
455 if (state == State::INVALID) {
467 state = State::AFTER_SIGN;
468 }
else if (c ==
'+') {
469 state = State::AFTER_SIGN;
470 }
else if (c ==
'.') {
471 state = State::LONELY_DOT;
472 }
else if (c.isDigit()) {
473 valueAbs =
static_cast<UnsignedT
>(c.digitValue());
474 state = State::INT_PART;
476 state = State::INVALID;
480 case State::AFTER_SIGN:
482 state = State::LONELY_DOT;
483 }
else if (c.isDigit()) {
484 valueAbs =
static_cast<UnsignedT
>(c.digitValue());
485 state = State::INT_PART;
487 state = State::INVALID;
491 case State::LONELY_DOT:
493 valueAbs =
static_cast<UnsignedT
>(c.digitValue());
495 state = State::FRAC_PART;
497 state = State::INVALID;
501 case State::INT_PART:
503 state = State::FRAC_PART;
504 }
else if (c ==
'e' || c ==
'E') {
506 }
else if (c.isDigit()) {
507 UnsignedT digit =
static_cast<UnsignedT
>(c.digitValue());
508 if (valueAbs > (max_u / 10)) {
510 state = State::INVALID;
514 if (valueAbs > (max_u - digit)) {
516 state = State::INVALID;
521 state = State::INVALID;
525 case State::FRAC_PART:
526 if (c ==
'e' || c ==
'E') {
528 }
else if (c.isDigit()) {
529 UnsignedT digit =
static_cast<UnsignedT
>(c.digitValue());
530 if (valueAbs > (max_u / 10)) {
532 state = State::INVALID;
536 if (valueAbs > (max_u - digit)) {
538 state = State::INVALID;
544 state = State::INVALID;
551 state = State::EXP_AFTER_SIGN;
552 }
else if (c ==
'+') {
553 state = State::EXP_AFTER_SIGN;
554 }
else if (c.isDigit()) {
555 exp =
static_cast<quint32
>(c.digitValue());
556 state = State::EXP_DIGITS;
558 state = State::INVALID;
562 case State::EXP_AFTER_SIGN:
564 exp =
static_cast<quint32
>(c.digitValue());
565 state = State::EXP_DIGITS;
567 state = State::INVALID;
571 case State::EXP_DIGITS:
573 quint32 digit =
static_cast<quint32
>(c.digitValue());
574 if (exp > (maxExp / 10)) {
576 state = State::INVALID;
580 if (exp > (maxExp - digit)) {
582 state = State::INVALID;
587 state = State::INVALID;
596 case State::AFTER_SIGN:
597 case State::LONELY_DOT:
599 case State::EXP_AFTER_SIGN:
603 case State::INT_PART:
604 case State::FRAC_PART:
605 case State::EXP_DIGITS:
610 quint32 expOffsetAbs;
612 expOffsetAbs = -
static_cast<quint32
>(expOffset);
614 expOffsetAbs =
static_cast<quint32
>(expOffset);
617 if (expSign == (expOffset < 0)) {
618 if (exp > (maxExp - expOffsetAbs)) {
625 if (exp < expOffsetAbs) {
639 for (quint32 i = 0; i < exp; i++) {
640 if ((valueAbs % 10) != 0) {
648 for (quint32 i = 0; i < exp; i++) {
649 if (valueAbs > (max_u / 10)) {
659 if (valueAbs >
static_cast<UnsignedT
>(min)) {
662 result =
static_cast<T
>(-valueAbs);
665 if (valueAbs >
static_cast<UnsignedT
>(max)) {
668 result =
static_cast<T
>(valueAbs);
678 tr(
"Invalid fixed point number string: \"%1\"").arg(str));
688 const QString& input,
689 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:76
The Length class is used to represent a length (for example 12.75 millimeters)
Definition length.h:82
The Point class is used to represent a point/coordinate/vector, for example (1.2mm; 5....
Definition point.h:78
The RuntimeError class.
Definition exceptions.h:218
Definition occmodel.cpp:77
type_safe::constrained_type< Length, UnsignedLengthConstraint, UnsignedLengthVerifier > UnsignedLength
Definition length.h:694