11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
22PROMEKI_NAMESPACE_BEGIN
47template <
typename T>
class Size2DTemplate {
50 Size2DTemplate(
const T &width = 0,
const T &height = 0) : _width(width), _height(height) {}
56 bool isValid()
const {
return (_width > 0) && (_height > 0); }
59 void set(
const T &w,
const T &h) {
66 void setWidth(
const T &val) {
72 const T &width()
const {
return _width; }
75 void setHeight(
const T &val) {
81 const T &height()
const {
return _height; }
84 T area()
const {
return _width * _height; }
87 String toString()
const {
return String::number(_width) +
"x" + String::number(_height); }
90 operator String()
const {
return toString(); }
104 static Result<Size2DTemplate<T>> fromString(
const String &str) {
105 const char *s = str.cstr();
106 if (s ==
nullptr || *s ==
'\0') {
107 return makeError<Size2DTemplate<T>>(Error::Invalid);
110 const char *end =
nullptr;
111 if (!parseDim(s, w, end)) {
112 return makeError<Size2DTemplate<T>>(Error::Invalid);
114 if (*end !=
'x' && *end !=
'X') {
115 return makeError<Size2DTemplate<T>>(Error::Invalid);
117 const char *rest = end + 1;
119 return makeError<Size2DTemplate<T>>(Error::Invalid);
122 if (!parseDim(rest, h, end) || *end !=
'\0') {
123 return makeError<Size2DTemplate<T>>(Error::Invalid);
125 return makeResult(Size2DTemplate<T>(w, h));
129 bool operator==(
const Size2DTemplate &other)
const {
130 return _width == other._width && _height == other._height;
134 bool operator!=(
const Size2DTemplate &other)
const {
return !(*
this == other); }
137 template <
typename N>
bool pointIsInside(
const Point<N, 2> &p)
const {
141 if (p.x() < N{0} || p.y() < N{0})
return false;
142 return static_cast<T
>(p.x()) < _width &&
static_cast<T
>(p.y()) < _height;
155 static bool parseDim(
const char *s, T &out,
const char *&end) {
156 char *parseEnd =
nullptr;
158 if constexpr (std::is_integral_v<T> && std::is_signed_v<T>) {
159 long long v = std::strtoll(s, &parseEnd, 10);
161 if (parseEnd == s || errno != 0)
return false;
162 out =
static_cast<T
>(v);
164 }
else if constexpr (std::is_integral_v<T>) {
170 while (*p ==
' ' || *p ==
'\t') ++p;
171 if (*p ==
'-')
return false;
172 unsigned long long v = std::strtoull(s, &parseEnd, 10);
174 if (parseEnd == s || errno != 0)
return false;
175 out =
static_cast<T
>(v);
178 double v = std::strtod(s, &parseEnd);
180 if (parseEnd == s || errno != 0)
return false;
181 out =
static_cast<T
>(v);
188using Size2Di32 = Size2DTemplate<int32_t>;
190using Size2Du32 = Size2DTemplate<uint32_t>;
192using Size2Df = Size2DTemplate<float>;
194using Size2Dd = Size2DTemplate<double>;
207struct std::formatter<promeki::Size2DTemplate<T>> : promeki::ToStringFormatter<promeki::Size2DTemplate<T>> {};