HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
unicode_line_break.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
8#pragma once
9
10#include "unicode_break_opportunity.hpp"
11#include "ucd_general_categories.hpp"
12#include "ucd_grapheme_cluster_breaks.hpp"
13#include "ucd_line_break_classes.hpp"
14#include "ucd_east_asian_widths.hpp"
15#include "../utility/module.hpp"
16#include <cstdint>
17#include <vector>
18#include <algorithm>
19#include <numeric>
20
21namespace hi::inline v1 {
22namespace detail {
23
27 unicode_line_break_class original_class = unicode_line_break_class::XX;
28 unicode_line_break_class current_class = unicode_line_break_class::XX;
29 bool is_extended_pictographic = false;
30 bool is_Cn = false;
31 unicode_east_asian_width east_asian_width = unicode_east_asian_width::A;
32
33 constexpr unicode_line_break_info() noexcept = default;
34 constexpr unicode_line_break_info(unicode_line_break_info const&) noexcept = default;
35 constexpr unicode_line_break_info(unicode_line_break_info&&) noexcept = default;
36 constexpr unicode_line_break_info& operator=(unicode_line_break_info const&) noexcept = default;
37 constexpr unicode_line_break_info& operator=(unicode_line_break_info&&) noexcept = default;
38
39 constexpr explicit unicode_line_break_info(
40 unicode_line_break_class break_class,
41 bool is_Cn,
42 bool is_extended_pictographic,
43 unicode_east_asian_width east_asian_width) noexcept :
44 original_class(break_class),
45 current_class(break_class),
46 is_Cn(is_Cn),
47 is_extended_pictographic(is_extended_pictographic),
48 east_asian_width(east_asian_width)
49 {
50 }
51
52 constexpr explicit operator unicode_line_break_class() const noexcept
53 {
54 return current_class;
55 }
56
57 constexpr unicode_line_break_info& operator|=(unicode_line_break_class rhs) noexcept
58 {
59 current_class = rhs;
60 return *this;
61 }
62
63 [[nodiscard]] constexpr bool operator==(unicode_line_break_class rhs) const noexcept
64 {
65 return current_class == rhs;
66 }
67
68 [[nodiscard]] constexpr bool operator==(unicode_east_asian_width rhs) const noexcept
69 {
70 return east_asian_width == rhs;
71 }
72};
73
75using unicode_line_break_info_iterator = unicode_line_break_info_vector::iterator;
76using unicode_line_break_info_const_iterator = unicode_line_break_info_vector::const_iterator;
77
78template<typename It, typename ItEnd, typename CodePointFunc>
79[[nodiscard]] constexpr std::vector<unicode_line_break_info>
80unicode_LB1(It first, ItEnd last, CodePointFunc const& code_point_func) noexcept
81{
83 r.reserve(std::distance(first, last));
84
85 for (auto it = first; it != last; ++it) {
86 hilet code_point = code_point_func(*it);
87 hilet east_asian_width = ucd_get_east_asian_width(code_point);
88 hilet break_class = ucd_get_line_break_class(code_point);
89 hilet general_category = ucd_get_general_category(code_point);
90 hilet grapheme_cluster_break = ucd_get_grapheme_cluster_break(code_point);
91
92 hilet resolved_break_class = [&]() {
93 switch (break_class) {
94 using enum unicode_line_break_class;
95 case AI:
96 case SG:
97 case XX:
98 return AL;
99 case CJ:
100 return NS;
101 case SA:
102 return is_Mn_or_Mc(general_category) ? CM : AL;
103 default:
104 return break_class;
105 }
106 }();
107
108 r.emplace_back(
109 resolved_break_class,
110 general_category == unicode_general_category::Cn,
111 grapheme_cluster_break == unicode_grapheme_cluster_break::Extended_Pictographic,
112 east_asian_width);
113 }
114
115 return r;
116}
117
118[[nodiscard]] constexpr void unicode_LB2_3(unicode_break_vector& opportunities) noexcept
119{
120 hi_axiom(not opportunities.empty());
121 // LB2
122 opportunities.front() = unicode_break_opportunity::no;
123 // LB3
124 opportunities.back() = unicode_break_opportunity::mandatory;
125}
126
127template<typename MatchFunc>
128constexpr void unicode_LB_walk(
129 unicode_break_vector& opportunities,
131 MatchFunc match_func) noexcept
132{
133 using enum unicode_line_break_class;
134
135 if (infos.empty()) {
136 return;
137 }
138
139 auto cur = infos.begin();
140 hilet last = infos.end() - 1;
141 hilet last2 = infos.end();
142 auto opportunity = opportunities.begin() + 1;
143
144 auto cur_sp_class = XX;
145 auto cur_nu_class = XX;
146 auto prev_class = XX;
147 auto num_ri = 0_uz;
148 while (cur != last) {
149 hilet next = cur + 1;
150 hilet cur_class = unicode_line_break_class{*cur};
151 hilet next2_class = cur + 2 == last2 ? XX : unicode_line_break_class{*(cur + 2)};
152
153 // Keep track of classes followed by zero or more SP.
154 if (cur_class != SP) {
155 cur_sp_class = cur_class;
156 }
157
158 // Keep track of a "NU (NU|SY|IS)*" and "NU (NU|SY|IS)* (CL|CP)?".
159 if (cur_nu_class == CL) {
160 // Only a single CL|CP class may be at the end, then the number is closed.
161 cur_nu_class = XX;
162 } else if (cur_nu_class == NU) {
163 if (cur_class == CL or cur_class == CP) {
164 cur_nu_class = CL;
165 } else if (cur_class != NU and cur_class != SY and cur_class != IS) {
166 cur_nu_class = XX;
167 }
168 } else if (cur_class == NU) {
169 cur_nu_class = NU;
170 }
171
172 // Keep track of consecutive RI, but only count the actual RIs.
173 if (cur->original_class == RI) {
174 ++num_ri;
175 } else if (*cur != RI) {
176 num_ri = 0;
177 }
178
179 if (*opportunity == unicode_break_opportunity::unassigned) {
180 *opportunity = match_func(prev_class, cur, next, next2_class, cur_sp_class, cur_nu_class, num_ri);
181 }
182
183 prev_class = cur_class;
184 cur = next;
185 ++opportunity;
186 }
187}
188
189constexpr void unicode_LB4_8a(unicode_break_vector& opportunities, std::vector<unicode_line_break_info> const& infos) noexcept
190{
191 unicode_LB_walk(
192 opportunities, infos, [](hilet prev, hilet cur, hilet next, hilet next2, hilet cur_sp, hilet cur_nu, hilet num_ri) {
193 using enum unicode_break_opportunity;
194 using enum unicode_line_break_class;
195 if (*cur == BK) {
196 return mandatory; // LB4: 4.0
197 } else if (*cur == CR and *next == LF) {
198 return no; // LB5: 5.01
199 } else if (*cur == CR or *cur == LF or *cur == NL) {
200 return mandatory; // LB5: 5.02, 5.03, 5.04
201 } else if (*next == BK or *next == CR or *next == LF or *next == NL) {
202 return no; // LB6: 6.0
203 } else if (*next == SP or *next == ZW) {
204 return no; // LB7: 7.01, 7.02
205 } else if (cur_sp == ZW) {
206 return yes; // LB8: 8.0
207 } else if (*cur == ZWJ) {
208 return no; // LB8a: 8.1
209 } else {
210 return unassigned;
211 }
212 });
213}
214
215constexpr void unicode_LB9(unicode_break_vector& opportunities, std::vector<unicode_line_break_info>& infos) noexcept
216{
217 using enum unicode_line_break_class;
218 using enum unicode_break_opportunity;
219
220 if (infos.empty()) {
221 return;
222 }
223
224 auto cur = infos.begin();
225 hilet last = infos.end() - 1;
226 auto opportunity = opportunities.begin() + 1;
227
228 auto X = XX;
229 while (cur != last) {
230 hilet next = cur + 1;
231
232 if ((*cur == CM or *cur == ZWJ) and X != XX) {
233 // Treat all CM/ZWJ as X (if there is an X).
234 *cur |= X;
235 } else {
236 // Reset X on non-CM/ZWJ.
237 X = XX;
238 }
239
240 if ((*cur != BK and *cur != CR and *cur != LF and *cur != NL and *cur != SP and *cur != ZW) and
241 (*next == CM or *next == ZWJ)) {
242 // [^BK CR LF NL SP ZW] x [CM ZWJ]*
243 *opportunity = no;
244
245 if (X == XX) {
246 // The first character of [^BK CR LF NL SP ZW] x [CM ZWJ]* => X
247 X = static_cast<unicode_line_break_class>(*cur);
248 }
249 }
250
251 cur = next;
252 ++opportunity;
253 }
254}
255
256constexpr void unicode_LB10(std::vector<unicode_line_break_info>& infos) noexcept
257{
258 using enum unicode_line_break_class;
259
260 for (auto& x : infos) {
261 if (x == CM or x == ZWJ) {
262 x |= AL;
263 }
264 }
265}
266
267constexpr void unicode_LB11_31(unicode_break_vector& opportunities, std::vector<unicode_line_break_info> const& infos) noexcept
268{
269 unicode_LB_walk(
270 opportunities, infos, [&](hilet prev, hilet cur, hilet next, hilet next2, hilet cur_sp, hilet cur_nu, hilet num_ri) {
271 using enum unicode_break_opportunity;
272 using enum unicode_line_break_class;
273 using enum unicode_east_asian_width;
274
275 if (*cur == WJ or *next == WJ) {
276 return no; // LB11: 11.01, 11.02
277 } else if (*cur == GL) {
278 return no; // LB12: 12.0
279 } else if (*cur != SP and *cur != BA and *cur != HY and *next == GL) {
280 return no; // LB12a: 12.1
281 } else if (*next == CL or *next == CP or *next == EX or *next == IS or *next == SY) {
282 return no; // LB13: 13.0
283 } else if (cur_sp == OP) {
284 return no; // LB14: 14.0
285 } else if (cur_sp == QU and *next == OP) {
286 return no; // LB15: 15.0
287 } else if ((cur_sp == CL or cur_sp == CP) and *next == NS) {
288 return no; // LB16: 16.0
289 } else if (cur_sp == B2 and *next == B2) {
290 return no; // LB17: 17.0
291 } else if (*cur == SP) {
292 return yes; // LB18: 18.0
293 } else if (*cur == QU or *next == QU) {
294 return no; // LB19: 19.01, 19.02
295 } else if (*cur == CB or *next == CB) {
296 return yes; // LB20: 20.01, 20.02
297 } else if (*cur == BB or *next == BA or *next == HY or *next == NS) {
298 return no; // LB21: 21.01, 21.02, 21.03, 21.04
299 } else if (prev == HL and (*cur == HY or *cur == BA)) {
300 return no; // LB21a: 21.1
301 } else if (*cur == SY and *next == HL) {
302 return no; // LB21b: 21.2
303 } else if (*next == IN) {
304 return no; // LB22: 22.0
305 } else if ((*cur == AL or *cur == HL) and *next == NU) {
306 return no; // LB23: 23.02
307 } else if (*cur == NU and (*next == AL or *next == HL)) {
308 return no; // LB23: 23.03
309 } else if (*cur == PR and (*next == ID or *next == EB or *next == EM)) {
310 return no; // LB23a: 23.12
311 } else if ((*cur == ID or *cur == EB or *cur == EM) and *next == PO) {
312 return no; // LB23a: 23.13
313 } else if ((*cur == PR or *cur == PO) and (*next == AL or *next == HL)) {
314 return no; // LB24: 24.02
315 } else if ((*cur == AL or *cur == HL) and (*next == PR or *next == PO)) {
316 return no; // LB24: 24.03
317 } else if (
318 (*cur == PR or *cur == PO) and ((*next == OP and next2 == NU) or (*next == HY and next2 == NU) or *next == NU)) {
319 return no; // LB25: 25.01
320 } else if ((*cur == OP or *cur == HY) and *next == NU) {
321 return no; // LB25: 25.02
322 } else if (*cur == NU and (*next == NU or *next == SY or *next == IS)) {
323 return no; // LB25: 25.03
324 } else if (cur_nu == NU and (*next == NU or *next == SY or *next == IS or *next == CL or *next == CP)) {
325 return no; // LB25: 25.04
326 } else if ((cur_nu == NU or cur_nu == CL) and (*next == PO or *next == PR)) {
327 return no; // LB25: 25.05
328 } else if (*cur == JL and (*next == JL or *next == JV or *next == H2 or *next == H3)) {
329 return no; // LB26: 26.01
330 } else if ((*cur == JV or *cur == H2) and (*next == JV or *next == JT)) {
331 return no; // LB26: 26.02
332 } else if ((*cur == JT or *cur == H3) and *next == JT) {
333 return no; // LB26: 26.03
334 } else if ((*cur == JL or *cur == JV or *cur == JT or *cur == H2 or *cur == H3) and *next == PO) {
335 return no; // LB27: 27.01
336 } else if (*cur == PR and (*next == JL or *next == JV or *next == JT or *next == H2 or *next == H3)) {
337 return no; // LB27: 27.02
338 } else if ((*cur == AL or *cur == HL) and (*next == AL or *next == HL)) {
339 return no; // LB28: 28.0
340 } else if (*cur == IS and (*next == AL or *next == HL)) {
341 return no; // LB29: 29.0
342 } else if ((*cur == AL or *cur == HL or *cur == NU) and (*next == OP and *next != F and *next != W and *next != H)) {
343 return no; // LB30: 30.01
344 } else if ((*cur == CP and *cur != F and *cur != W and *cur != H) and (*next == AL or *next == HL or *next == NU)) {
345 return no; // LB30: 30.02
346 } else if (*cur == RI and *next == RI and (num_ri % 2) == 1) {
347 return no; // LB30a: 30.11, 30.12, 30.13
348 } else if (*cur == EB and *next == EM) {
349 return no; // LB30b: 30.21
350 } else if (cur->is_extended_pictographic and cur->is_Cn and *next == EM) {
351 return no; // LB30b: 30.22
352 } else {
353 return yes; // LB31: 999.0
354 }
355 });
356}
357
364[[nodiscard]] constexpr float
365unicode_LB_width(std::vector<float>::const_iterator first, std::vector<float>::const_iterator last) noexcept
366{
367 if (first == last) {
368 return 0.0f;
369 }
370
371 auto rfirst = std::make_reverse_iterator(last);
372 auto rlast = std::make_reverse_iterator(first);
373
374 auto it = std::find_if(rfirst, rlast, [](hilet& width) {
375 return width >= 0.0;
376 });
377 return std::accumulate(it, rlast, 0.0f, [](float acc, hilet& width) {
378 return acc + abs(width);
379 });
380}
381
388[[nodiscard]] constexpr float unicode_LB_width(std::vector<float> const& widths, std::vector<size_t> const& lengths)
389{
390 auto max_width = 0.0f;
391 auto it = widths.begin();
392 for (auto length : lengths) {
393 inplace_max(max_width, unicode_LB_width(it, it + length));
394 it += length;
395 }
396 return max_width;
397}
398
406[[nodiscard]] constexpr bool
407unicode_LB_width_check(std::vector<float> const& widths, std::vector<size_t> const& lengths, float maximum_line_width) noexcept
408{
409 auto it = widths.begin();
410 for (auto length : lengths) {
411 if (unicode_LB_width(it, it + length) > maximum_line_width) {
412 return false;
413 }
414 it += length;
415 }
416 return true;
417}
418
423[[nodiscard]] constexpr std::vector<size_t> unicode_LB_mandatory_lines(unicode_break_vector const& opportunities) noexcept
424{
425 auto r = std::vector<size_t>{};
426
427 auto length = 0_uz;
428 for (auto it = opportunities.begin() + 1; it != opportunities.end(); ++it) {
429 ++length;
430 if (*it == unicode_break_opportunity::mandatory) {
431 r.push_back(length);
432 length = 0_uz;
433 }
434 }
435
436 return r;
437}
438
443[[nodiscard]] constexpr std::vector<size_t> unicode_LB_optional_lines(unicode_break_vector const& opportunities) noexcept
444{
445 auto r = std::vector<size_t>{};
446
447 auto length = 0_uz;
448 for (auto it = opportunities.begin() + 1; it != opportunities.end(); ++it) {
449 ++length;
450 if (*it != unicode_break_opportunity::no) {
451 r.push_back(length);
452 length = 0_uz;
453 }
454 }
455
456 return r;
457}
458
459[[nodiscard]] constexpr unicode_break_const_iterator unicode_LB_fast_fit_line(
460 unicode_break_const_iterator opportunity_it,
461 std::vector<float>::const_iterator width_it,
462 float maximum_line_width) noexcept
463{
464 using enum unicode_break_opportunity;
465
466 auto width = 0.0f;
467 auto end_of_line = opportunity_it;
468 while (true) {
469 width += abs(*width_it);
470 if (width > maximum_line_width) {
471 // This character makes the width too long.
472 return end_of_line;
473
474 } else if (*opportunity_it == mandatory) {
475 // This character is an end-of-line.
476 return opportunity_it;
477
478 } else if (*opportunity_it == yes) {
479 // This character is a valid break opportunity.
480 end_of_line = opportunity_it;
481 }
482
483 ++opportunity_it;
484 ++width_it;
485 }
486 hi_unreachable();
487}
488
489[[nodiscard]] constexpr unicode_break_const_iterator unicode_LB_slow_fit_line(
490 unicode_break_const_iterator first,
491 unicode_break_const_iterator end_of_line,
492 std::vector<float>::const_iterator first_width,
493 float maximum_line_width) noexcept
494{
495 using enum unicode_break_opportunity;
496
497 // Carefully look forward for a break opportunity.
498 auto it = end_of_line;
499 while (true) {
500 hilet num_characters = std::distance(first, it + 1);
501 hilet line_width = unicode_LB_width(first_width, first_width + num_characters);
502
503 if (line_width <= maximum_line_width) {
504 if (*it == mandatory) {
505 // The next mandatory break fits in the maximum width.
506 return it;
507
508 } else if (*it == yes) {
509 // The next break opportunity fits in the maximum width.
510 end_of_line = it;
511 }
512 } else {
513 // This break opportunity doesn't fit within the maximum width. Use the previous break opportunity.
514 return end_of_line;
515 }
516
517 ++it;
518 }
519 hi_unreachable();
520}
521
522[[nodiscard]] constexpr unicode_break_const_iterator
523unicode_LB_finish_fit_line(unicode_break_const_iterator first, unicode_break_const_iterator end_of_line) noexcept
524{
525 if (first == end_of_line) {
526 // We couldn't break the line to fit the maximum line width.
527 while (*end_of_line == unicode_break_opportunity::no) {
528 ++end_of_line;
529 }
530 }
531
532 // Return iterator past the end-of-line.
533 return end_of_line + 1;
534}
535
541 unicode_break_vector const& opportunities,
542 std::vector<float> const& widths,
543 float maximum_line_width) noexcept
544{
545 using enum unicode_break_opportunity;
546
547 auto r = std::vector<size_t>{};
548 if (widths.empty()) {
549 return r;
550 }
551
552 auto opportunity_it = opportunities.begin() + 1;
553 auto width_it = widths.begin();
554 while (width_it != widths.end()) {
555 // First quickly find when the line is too long.
556 auto opportunity_eol = unicode_LB_fast_fit_line(opportunity_it, width_it, maximum_line_width);
557 opportunity_eol = unicode_LB_slow_fit_line(opportunity_it, opportunity_eol, width_it, maximum_line_width);
558 opportunity_eol = unicode_LB_finish_fit_line(opportunity_it, opportunity_eol);
559
560 hilet num_characters = std::distance(opportunity_it, opportunity_eol);
561 r.push_back(num_characters);
562 opportunity_it += num_characters;
563 width_it += num_characters;
564 }
565
566 return r;
567}
568
577[[nodiscard]] constexpr std::pair<float, std::vector<size_t>>
578unicode_LB_maximum_width(unicode_break_vector const& opportunities, std::vector<float> const& char_widths)
579{
580 auto line_lengths = detail::unicode_LB_mandatory_lines(opportunities);
581 hilet width = detail::unicode_LB_width(char_widths, line_lengths);
582 return {width, std::move(line_lengths)};
583}
584
593[[nodiscard]] constexpr std::pair<float, std::vector<size_t>>
594unicode_LB_minimum_width(unicode_break_vector const& opportunities, std::vector<float> const& char_widths)
595{
596 auto line_lengths = detail::unicode_LB_optional_lines(opportunities);
597 hilet width = detail::unicode_LB_width(char_widths, line_lengths);
598 return {width, std::move(line_lengths)};
599}
600
610[[nodiscard]] constexpr std::pair<float, std::vector<size_t>>
611unicode_LB_width(unicode_break_vector const& opportunities, std::vector<float> const& char_widths, float maximum_line_width)
612{
613 auto line_lengths = detail::unicode_LB_fit_lines(opportunities, char_widths, maximum_line_width);
614 hilet width = detail::unicode_LB_width(char_widths, line_lengths);
615 return {width, std::move(line_lengths)};
616}
617
618} // namespace detail
619
627template<typename It, typename ItEnd, typename CodePointFunc>
628[[nodiscard]] inline unicode_break_vector
629unicode_line_break(It first, ItEnd last, CodePointFunc const& code_point_func) noexcept
630{
631 auto size = narrow_cast<size_t>(std::distance(first, last));
632 auto r = unicode_break_vector{size + 1, unicode_break_opportunity::unassigned};
633
634 auto infos = detail::unicode_LB1(first, last, code_point_func);
635 detail::unicode_LB2_3(r);
636 detail::unicode_LB4_8a(r, infos);
637 detail::unicode_LB9(r, infos);
638 detail::unicode_LB10(infos);
639 detail::unicode_LB11_31(r, infos);
640 return r;
641}
642
650[[nodiscard]] constexpr std::vector<size_t>
651unicode_line_break(unicode_break_vector const& opportunities, std::vector<float> const& widths, float maximum_line_width)
652{
653 // See if the lines after mandatory breaks will fit the width and return.
654 auto r = detail::unicode_LB_mandatory_lines(opportunities);
655 if (detail::unicode_LB_width_check(widths, r, maximum_line_width)) {
656 return r;
657 }
658
659 r = detail::unicode_LB_fit_lines(opportunities, widths, maximum_line_width);
660 hi_axiom(detail::unicode_LB_width_check(widths, r, maximum_line_width));
661 return r;
662}
663
664
665} // namespace hi::inline v1
constexpr float unicode_LB_width(std::vector< float >::const_iterator first, std::vector< float >::const_iterator last) noexcept
Calculate the width of a line.
Definition unicode_line_break.hpp:365
constexpr std::vector< size_t > unicode_LB_mandatory_lines(unicode_break_vector const &opportunities) noexcept
Get the length of each line when broken with mandatory breaks.
Definition unicode_line_break.hpp:423
constexpr std::vector< size_t > unicode_LB_optional_lines(unicode_break_vector const &opportunities) noexcept
Get the length of each line when broken with mandatory and optional breaks.
Definition unicode_line_break.hpp:443
constexpr std::pair< float, std::vector< size_t > > unicode_LB_minimum_width(unicode_break_vector const &opportunities, std::vector< float > const &char_widths)
Get the minimum width of the text.
Definition unicode_line_break.hpp:594
constexpr std::pair< float, std::vector< size_t > > unicode_LB_maximum_width(unicode_break_vector const &opportunities, std::vector< float > const &char_widths)
Get the maximum width of the text.
Definition unicode_line_break.hpp:578
constexpr std::vector< size_t > unicode_LB_fit_lines(unicode_break_vector const &opportunities, std::vector< float > const &widths, float maximum_line_width) noexcept
Get the length of each line when broken after folding text to a maximum width.
Definition unicode_line_break.hpp:540
constexpr bool unicode_LB_width_check(std::vector< float > const &widths, std::vector< size_t > const &lengths, float maximum_line_width) noexcept
Check if all the lines in the text fit the maximum width.
Definition unicode_line_break.hpp:407
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
unicode_break_vector unicode_line_break(It first, ItEnd last, CodePointFunc const &code_point_func) noexcept
The unicode line break algorithm UAX #14.
Definition unicode_line_break.hpp:629
unicode_line_break_class
Unicode line break class.
Definition ucd_line_break_classes.hpp:1012
Combined unicode_line_break_class and unicode_line_break_opportunity.
Definition unicode_line_break.hpp:26
T accumulate(T... args)
T begin(T... args)
T distance(T... args)
T find_if(T... args)
T move(T... args)
T next(T... args)
T reserve(T... args)