32constexpr T clamp(
const T& x,
const T& a,
const T& b)
47#if DL_PLATFORM == DL_PLATFORM_LINUX
50 return std::clamp<T>(x, 0, 1);
60 return x >= 0 && x <= 1;
70 a[1] * b[2] - a[2] * b[1],
71 a[2] * b[0] - a[0] * b[2],
72 a[0] * b[1] - a[1] * b[0] };
85 return dynamic_cast<T>(p);
92template<
typename T,
size_t N>
96 for (
int i = 0; i !=
N; ++i)
110#if DL_PLATFORM == DL_PLATFORM_WIN32
111 return std::as_const(a);
125template<
typename T,
typename V>
128 auto iter = find(container.rbegin(), container.rend(), a);
130 if (iter != container.rend())
131 container.erase(container.begin(), iter.base());
142template<PopFrontAble C,
typename F>
145 while (!container.empty())
147 auto iter = container.front();
148 container.pop_front();
243 for (
auto iter = container.begin(); iter != container.end(); ++iter)
247 for (; iter1 < container.end(); ++iter1)
253 return container.end();
261template<
typename T,
typename V>
264 if (container.size() <= per_num)
267 size_t num = (container.size() - 1) / per_num;
269 ret.resize(num + container.size());
272 auto iter = container.begin();
273 auto iter_ret = ret.begin();
274 while (iter != container.end())
276 *iter_ret++ = *iter++;
280 && i < container.size())
292template<
typename T,
typename V>
295 if (container.size() <= per_num)
298 size_t num = (container.size() - 1) / per_num;
300 ret.resize(num + container.size());
303 auto iter = container.rbegin();
304 auto iter_ret = ret.rbegin();
305 while (iter != container.rend())
307 *iter_ret++ = *iter++;
311 && i < container.size())
332template<
typename T,
typename V>
333void split(
const T& container,
V delimiter, std::vector<T>& ret)
335 if (container.empty())
339 auto iter_begin = container.begin();
344 if (*iter_begin == delimiter)
347 if (++iter_begin == container.end())
356 auto iter_find = std::find(iter_begin, container.end(), delimiter);
358 if (iter_find == container.end())
360 ret.push_back(
T(iter_begin, container.end()));
365 ret.push_back(
T(iter_begin, iter_find));
366 iter_begin = iter_find + 1;
367 if (iter_begin == container.end())
369 ret.push_back(
T(iter_begin, container.end()));
389template<
typename T,
typename V>
392 if (container.empty())
396 auto iter_begin = container.begin();
401 if (*iter_begin == delimiter)
403 if (++iter_begin == container.end())
409 auto iter_find = std::find(iter_begin, container.end(), delimiter);
411 if (iter_find == container.end())
413 ret.push_back(
T(iter_begin, container.end()));
418 ret.push_back(
T(iter_begin, iter_find));
419 iter_begin = iter_find + 1;
420 if (iter_begin == container.end())
437void split_sub(
const T& container,
const T& delimiter, std::vector<T>& ret)
439 if (container.empty())
441 assert(!delimiter.empty());
443 auto iter_pre = container.begin();
444 auto iter_d = delimiter.begin();
447 auto iter_cur = iter_pre;
449 auto iter_cat = iter_pre;
455 if (iter_cur == container.end())
457 ret.push_back(
T(iter_pre, iter_cur));
460 if (*iter_cur == *iter_d)
475 if (iter_d == delimiter.end())
477 ret.push_back(
T(iter_pre, iter_cat));
479 iter_d = delimiter.begin();
484 if (iter_cur == container.end())
486 ret.push_back(
T(iter_pre, iter_cur));
490 if (*iter_cur == *iter_d)
499 iter_d = delimiter.begin();
511template<
typename T,
typename V>
512void make_sequence(
T& c,
const std::initializer_list<std::initializer_list<V>>& vec)
514 for (
auto& iter : vec)
516 assert(iter.size() == 2);
518 const V& b = *(iter.begin() + 1);
535template<
typename C,
typename F>
538 if (container.empty())
543 auto iter_pre = std::begin(container);
544 auto iter_cur = std::next(iter_pre);
546 for (; iter_cur != std::end(container);)
548 func(*iter_pre, *iter_cur);
553 func(*iter_pre, *std::begin(container));
560template<
typename C,
typename F>
563 if (container.empty())
568 auto iter_pre = std::rbegin(container);
569 auto iter_cur = std::next(iter_pre);
571 for (; iter_cur != std::rend(container);)
573 func(*iter_pre, *iter_cur);
578 func(*iter_pre, *std::rbegin(container));
589template<IsPo
inter T,
typename FC,
typename F>
597 T node_this = s.top();
602 using C =
decltype(func_child(node_this));
603 C c = func_child(node_this);
604 for (
auto iter = c->rbegin(); iter != c->rend(); ++iter)
619 finally(
F&& func) : _func(func) {}
640template<
typename T,
size_t N>
672 static_assert(
N > 0 &&
N <= 11,
"字符串长度过长!");
674 for (
size_t i = 0; i <
N - 1; ++i)
678 if (ch >= 48 && ch <= 57)
680 else if (ch >= 65 && ch <= 90)
682 else if (ch >= 97 && ch <= 122)
689 assert(0 &&
"只能是字母、数字、下划线、点!");
691 ret |= ((uint64_t)ch << (i * 6));
类似std::array,增加xyzw、wh等成员访问
T r_insert_per_num(const T &container, V v, size_t per_num)
从后面往前,隔n个元素就插入1个值,首尾不会出现分割符
void split_no_empty(const T &container, V delimiter, std::vector< T > &ret)
以 元素 分割 容器
bool limit_bigger(Array< T, N > &a, const Array< T, N > &limit)
限制到大于某个值,如果修改了原值则返回true
void for_couple(const C &container, F func, bool ring=false)
成对遍历
void for_tree(T root, FC func_child, F func)
遍历树(使用栈,深度优先)
T cast_dynamic(void *p)
动态类型强转
void split_sub(const T &container, const T &delimiter, std::vector< T > &ret)
以 子串 分割 容器
constexpr T is_saturate(const T &x)
是否数值在[0, 1]
void for_couple_r(const C &container, F func, bool ring=false)
反向成对遍历
void make_sequence(T &c, const std::initializer_list< std::initializer_list< V > > &vec)
生成序列
void split(const T &container, V delimiter, std::vector< T > &ret)
以 元素 分割 容器
void operate_front(C &container, F func)
从容器container不断取出第一个元素,执行操作
const T & constant(T &v)
加上const修饰
constexpr Array< T, 3 > cross(const Array< T, 3 > &a, const Array< T, 3 > &b)
向量叉乘
constexpr T sign(const T &v)
返回符号,正数返回1、负数返回-1、0返回0
consteval uint64_t str_uid(const char(&str)[N])
固定条件的字符串,生成唯一id
T insert_per_num(const T &container, V v, size_t per_num)
隔n个元素就插入1个分割符,首尾不会出现分割符
constexpr T saturate(const T &x)
限制数值到 [0, 1]
constexpr T clamp(const T &x, const T &a, const T &b)
限制数值到 [a, b]
void erase_head_from_last(T &container, const V &a)
从容器container中移除 最后 匹配到的a元素 之前(包含a)的所有元素,如果没有匹配到,则什么都不做。
auto find_equal(C &container)
替换容器元素值
constexpr T & arr_last(const T(&arr)[N])
返回静态数组长度