| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098 |
- // <format> Formatting -*- C++ -*-
- // Copyright The GNU Toolchain Authors.
- //
- // This file is part of the GNU ISO C++ Library. This library is free
- // software; you can redistribute it and/or modify it under the
- // terms of the GNU General Public License as published by the
- // Free Software Foundation; either version 3, or (at your option)
- // any later version.
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // Under Section 7 of GPL version 3, you are granted additional
- // permissions described in the GCC Runtime Library Exception, version
- // 3.1, as published by the Free Software Foundation.
- // You should have received a copy of the GNU General Public License and
- // a copy of the GCC Runtime Library Exception along with this program;
- // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- // <http://www.gnu.org/licenses/>.
- /** @file include/format
- * This is a Standard C++ Library header.
- */
- #ifndef _GLIBCXX_FORMAT
- #define _GLIBCXX_FORMAT 1
- #pragma GCC system_header
- #include <bits/requires_hosted.h> // for std::string
- #if __cplusplus >= 202002L
- #include <array>
- #include <charconv>
- #include <concepts>
- #include <limits>
- #include <locale>
- #include <optional>
- #include <span>
- #include <string_view>
- #include <string>
- #include <variant> // monostate (TODO: move to bits/utility.h?)
- #include <bits/ranges_base.h> // input_range, range_reference_t
- #include <bits/ranges_algobase.h> // ranges::copy
- #include <bits/stl_iterator.h> // back_insert_iterator
- #include <bits/stl_pair.h> // __is_pair
- #include <bits/utility.h> // tuple_size_v
- #include <ext/numeric_traits.h> // __int_traits
- #if !__has_builtin(__builtin_toupper)
- # include <cctype>
- #endif
- namespace std _GLIBCXX_VISIBILITY(default)
- {
- _GLIBCXX_BEGIN_NAMESPACE_VERSION
- // 201907 Text Formatting, Integration of chrono, printf corner cases.
- // 202106 std::format improvements.
- // 202110 Fixing locale handling in chrono formatters, generator-like types.
- // 202207 Encodings in localized formatting of chrono, basic-format-string.
- #define __cpp_lib_format 202110L
- #define __cpp_lib_format_uchar 202311L
- #if __cplusplus > 202002L
- // 202207 P2286R8 Formatting Ranges
- // 202207 P2585R1 Improving default container formatting
- // TODO: #define __cpp_lib_format_ranges 202207L
- #endif
- // [format.context], class template basic_format_context
- template<typename _Out, typename _CharT> class basic_format_context;
- /// @cond undocumented
- namespace __format
- {
- // Type-erased character sink.
- template<typename _CharT> class _Sink;
- // Output iterator that writes to a type-erase character sink.
- template<typename _CharT>
- class _Sink_iter;
- } // namespace __format
- /// @endcond
- using format_context
- = basic_format_context<__format::_Sink_iter<char>, char>;
- using wformat_context
- = basic_format_context<__format::_Sink_iter<wchar_t>, wchar_t>;
- // [format.args], class template basic_format_args
- template<typename _Context> class basic_format_args;
- using format_args = basic_format_args<format_context>;
- using wformat_args = basic_format_args<wformat_context>;
- // [format.arguments], arguments
- // [format.arg], class template basic_format_arg
- template<typename _Context>
- class basic_format_arg;
- // [format.fmt.string], class template basic_format_string
- /** A compile-time checked format string for the specified argument types.
- *
- * @since C++23 but available as an extension in C++20.
- */
- template<typename _CharT, typename... _Args>
- struct basic_format_string
- {
- template<typename _Tp>
- requires convertible_to<const _Tp&, basic_string_view<_CharT>>
- consteval
- basic_format_string(const _Tp& __s);
- [[__gnu__::__always_inline__]]
- constexpr basic_string_view<_CharT>
- get() const noexcept
- { return _M_str; }
- private:
- basic_string_view<_CharT> _M_str;
- };
- template<typename... _Args>
- using format_string = basic_format_string<char, type_identity_t<_Args>...>;
- template<typename... _Args>
- using wformat_string
- = basic_format_string<wchar_t, type_identity_t<_Args>...>;
- // [format.formatter], formatter
- /// The primary template of std::formatter is disabled.
- template<typename _Tp, typename _CharT = char>
- struct formatter
- {
- formatter() = delete; // No std::formatter specialization for this type.
- formatter(const formatter&) = delete;
- formatter& operator=(const formatter&) = delete;
- };
- // [format.error], class format_error
- class format_error : public runtime_error
- {
- public:
- explicit format_error(const string& __what) : runtime_error(__what) { }
- explicit format_error(const char* __what) : runtime_error(__what) { }
- };
- /// @cond undocumented
- [[noreturn]]
- inline void
- __throw_format_error(const char* __what)
- { _GLIBCXX_THROW_OR_ABORT(format_error(__what)); }
- namespace __format
- {
- // XXX use named functions for each constexpr error?
- [[noreturn]]
- inline void
- __unmatched_left_brace_in_format_string()
- { __throw_format_error("format error: unmatched '{' in format string"); }
- [[noreturn]]
- inline void
- __unmatched_right_brace_in_format_string()
- { __throw_format_error("format error: unmatched '}' in format string"); }
- [[noreturn]]
- inline void
- __conflicting_indexing_in_format_string()
- { __throw_format_error("format error: conflicting indexing style in format string"); }
- [[noreturn]]
- inline void
- __invalid_arg_id_in_format_string()
- { __throw_format_error("format error: invalid arg-id in format string"); }
- [[noreturn]]
- inline void
- __failed_to_parse_format_spec()
- { __throw_format_error("format error: failed to parse format-spec"); }
- } // namespace __format
- /// @endcond
- // [format.parse.ctx], class template basic_format_parse_context
- template<typename _CharT> class basic_format_parse_context;
- using format_parse_context = basic_format_parse_context<char>;
- using wformat_parse_context = basic_format_parse_context<wchar_t>;
- template<typename _CharT>
- class basic_format_parse_context
- {
- public:
- using char_type = _CharT;
- using const_iterator = typename basic_string_view<_CharT>::const_iterator;
- using iterator = const_iterator;
- constexpr explicit
- basic_format_parse_context(basic_string_view<_CharT> __fmt,
- size_t __num_args = 0) noexcept
- : _M_begin(__fmt.begin()), _M_end(__fmt.end()), _M_num_args(__num_args)
- { }
- basic_format_parse_context(const basic_format_parse_context&) = delete;
- void operator=(const basic_format_parse_context&) = delete;
- constexpr const_iterator begin() const noexcept { return _M_begin; }
- constexpr const_iterator end() const noexcept { return _M_end; }
- constexpr void
- advance_to(const_iterator __it) noexcept
- { _M_begin = __it; }
- constexpr size_t
- next_arg_id()
- {
- if (_M_indexing == _Manual)
- __format::__conflicting_indexing_in_format_string();
- _M_indexing = _Auto;
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3825. Missing compile-time argument id check in next_arg_id
- if (std::is_constant_evaluated())
- if (_M_next_arg_id == _M_num_args)
- __format::__invalid_arg_id_in_format_string();
- return _M_next_arg_id++;
- }
- constexpr void
- check_arg_id(size_t __id)
- {
- if (_M_indexing == _Auto)
- __format::__conflicting_indexing_in_format_string();
- _M_indexing = _Manual;
- if (std::is_constant_evaluated())
- if (__id >= _M_num_args)
- __format::__invalid_arg_id_in_format_string();
- }
- private:
- iterator _M_begin;
- iterator _M_end;
- enum _Indexing { _Unknown, _Manual, _Auto };
- _Indexing _M_indexing = _Unknown;
- size_t _M_next_arg_id = 0;
- size_t _M_num_args;
- };
- /// @cond undocumented
- template<typename _Tp, template<typename...> class _Class>
- static constexpr bool __is_specialization_of = false;
- template<template<typename...> class _Class, typename... _Args>
- static constexpr bool __is_specialization_of<_Class<_Args...>, _Class>
- = true;
- namespace __format
- {
- // pre: first != last
- template<typename _CharT>
- constexpr pair<unsigned short, const _CharT*>
- __parse_integer(const _CharT* __first, const _CharT* __last)
- {
- if (__first == __last)
- __builtin_unreachable();
- if constexpr (is_same_v<_CharT, char>)
- {
- const auto __start = __first;
- unsigned short __val = 0;
- // N.B. std::from_chars is not constexpr in C++20.
- if (__detail::__from_chars_alnum<true>(__first, __last, __val, 10)
- && __first != __start) [[likely]]
- return {__val, __first};
- }
- else
- {
- constexpr int __n = 32;
- char __buf[__n]{};
- for (int __i = 0; __i < __n && (__first + __i) != __last; ++__i)
- __buf[__i] = __first[__i];
- auto [__v, __ptr] = __format::__parse_integer(__buf, __buf + __n);
- if (__ptr) [[likely]]
- return {__v, __first + (__ptr - __buf)};
- }
- return {0, nullptr};
- }
- template<typename _CharT>
- constexpr pair<unsigned short, const _CharT*>
- __parse_arg_id(const _CharT* __first, const _CharT* __last)
- {
- if (__first == __last)
- __builtin_unreachable();
- if (*__first == '0')
- return {0, __first + 1}; // No leading zeros allowed, so '0...' == 0
- if ('1' <= *__first && *__first <= '9')
- {
- const unsigned short __id = *__first - '0';
- const auto __next = __first + 1;
- // Optimize for most likely case of single digit arg-id.
- if (__next == __last || !('0' <= *__next && *__next <= '9'))
- return {__id, __next};
- else
- return __format::__parse_integer(__first, __last);
- }
- return {0, nullptr};
- }
- enum _Pres_type {
- _Pres_none = 0, // Default type (not valid for integer presentation types).
- // Presentation types for integral types (including bool and charT).
- _Pres_d = 1, _Pres_b, _Pres_B, _Pres_o, _Pres_x, _Pres_X, _Pres_c,
- // Presentation types for floating-point types.
- _Pres_a = 1, _Pres_A, _Pres_e, _Pres_E, _Pres_f, _Pres_F, _Pres_g, _Pres_G,
- _Pres_p = 0, _Pres_P, // For pointers.
- _Pres_s = 0, // For strings and bool.
- _Pres_esc = 0xf, // For strings and charT.
- };
- enum _Align {
- _Align_default,
- _Align_left,
- _Align_right,
- _Align_centre,
- };
- enum _Sign {
- _Sign_default,
- _Sign_plus,
- _Sign_minus, // XXX does this need to be distinct from _Sign_default?
- _Sign_space,
- };
- enum _WidthPrec {
- _WP_none, // No width/prec specified.
- _WP_value, // Fixed width/prec specified.
- _WP_from_arg // Use a formatting argument for width/prec.
- };
- template<typename _Context>
- size_t
- __int_from_arg(const basic_format_arg<_Context>& __arg);
- constexpr bool __is_digit(char __c)
- { return std::__detail::__from_chars_alnum_to_val(__c) < 10; }
- constexpr bool __is_xdigit(char __c)
- { return std::__detail::__from_chars_alnum_to_val(__c) < 16; }
- template<typename _CharT>
- struct _Spec
- {
- _Align _M_align : 2;
- _Sign _M_sign : 2;
- unsigned _M_alt : 1;
- unsigned _M_localized : 1;
- unsigned _M_zero_fill : 1;
- _WidthPrec _M_width_kind : 2;
- _WidthPrec _M_prec_kind : 2;
- _Pres_type _M_type : 4;
- unsigned short _M_width;
- unsigned short _M_prec;
- _CharT _M_fill = ' ';
- using iterator = typename basic_string_view<_CharT>::iterator;
- static constexpr _Align
- _S_align(_CharT __c) noexcept
- {
- switch (__c)
- {
- case '<': return _Align_left;
- case '>': return _Align_right;
- case '^': return _Align_centre;
- default: return _Align_default;
- }
- }
- // pre: __first != __last
- constexpr iterator
- _M_parse_fill_and_align(iterator __first, iterator __last) noexcept
- {
- if (*__first != '{')
- {
- // TODO: accept any UCS scalar value as fill character.
- // If narrow source encoding is UTF-8 then accept multibyte char.
- if (__last - __first >= 2)
- {
- if (_Align __align = _S_align(__first[1]))
- {
- _M_fill = *__first;
- _M_align = __align;
- return __first + 2;
- }
- }
- if (_Align __align = _S_align(__first[0]))
- {
- _M_fill = ' ';
- _M_align = __align;
- return __first + 1;
- }
- }
- return __first;
- }
- static constexpr _Sign
- _S_sign(_CharT __c) noexcept
- {
- switch (__c)
- {
- case '+': return _Sign_plus;
- case '-': return _Sign_minus;
- case ' ': return _Sign_space;
- default: return _Sign_default;
- }
- }
- // pre: __first != __last
- constexpr iterator
- _M_parse_sign(iterator __first, iterator) noexcept
- {
- if (_Sign __sign = _S_sign(*__first))
- {
- _M_sign = __sign;
- return __first + 1;
- }
- return __first;
- }
- // pre: *__first is valid
- constexpr iterator
- _M_parse_alternate_form(iterator __first, iterator) noexcept
- {
- if (*__first == '#')
- {
- _M_alt = true;
- ++__first;
- }
- return __first;
- }
- // pre: __first != __last
- constexpr iterator
- _M_parse_zero_fill(iterator __first, iterator /* __last */) noexcept
- {
- if (*__first == '0')
- {
- _M_zero_fill = true;
- ++__first;
- }
- return __first;
- }
- // pre: __first != __last
- static constexpr iterator
- _S_parse_width_or_precision(iterator __first, iterator __last,
- unsigned short& __val, bool& __arg_id,
- basic_format_parse_context<_CharT>& __pc)
- {
- if (__format::__is_digit(*__first))
- {
- auto [__v, __ptr] = __format::__parse_integer(__first, __last);
- if (!__ptr)
- __throw_format_error("format error: invalid width or precision "
- "in format-spec");
- __first = __ptr;
- __val = __v;
- }
- else if (*__first == '{')
- {
- __arg_id = true;
- ++__first;
- if (__first == __last)
- __format::__unmatched_left_brace_in_format_string();
- if (*__first == '}')
- __val = __pc.next_arg_id();
- else
- {
- auto [__v, __ptr] = __format::__parse_arg_id(__first, __last);
- if (__ptr == nullptr || __ptr == __last || *__ptr != '}')
- __format::__invalid_arg_id_in_format_string();
- __first = __ptr;
- __pc.check_arg_id(__v);
- __val = __v;
- }
- ++__first; // past the '}'
- }
- return __first;
- }
- // pre: __first != __last
- constexpr iterator
- _M_parse_width(iterator __first, iterator __last,
- basic_format_parse_context<_CharT>& __pc)
- {
- bool __arg_id = false;
- if (*__first == '0')
- __throw_format_error("format error: width must be non-zero in "
- "format string");
- auto __next = _S_parse_width_or_precision(__first, __last, _M_width,
- __arg_id, __pc);
- if (__next != __first)
- _M_width_kind = __arg_id ? _WP_from_arg : _WP_value;
- return __next;
- }
- // pre: __first != __last
- constexpr iterator
- _M_parse_precision(iterator __first, iterator __last,
- basic_format_parse_context<_CharT>& __pc)
- {
- if (__first[0] != '.')
- return __first;
- iterator __next = ++__first;
- bool __arg_id = false;
- if (__next != __last)
- __next = _S_parse_width_or_precision(__first, __last, _M_prec,
- __arg_id, __pc);
- if (__next == __first)
- __throw_format_error("format error: missing precision after '.' in "
- "format string");
- _M_prec_kind = __arg_id ? _WP_from_arg : _WP_value;
- return __next;
- }
- // pre: __first != __last
- constexpr iterator
- _M_parse_locale(iterator __first, iterator /* __last */) noexcept
- {
- if (*__first == 'L')
- {
- _M_localized = true;
- ++__first;
- }
- return __first;
- }
- template<typename _Context>
- size_t
- _M_get_width(_Context& __ctx) const
- {
- size_t __width = 0;
- if (_M_width_kind == _WP_value)
- __width = _M_width;
- else if (_M_width_kind == _WP_from_arg)
- __width = __format::__int_from_arg(__ctx.arg(_M_width));
- return __width;
- }
- template<typename _Context>
- size_t
- _M_get_precision(_Context& __ctx) const
- {
- size_t __prec = -1;
- if (_M_prec_kind == _WP_value)
- __prec = _M_prec;
- else if (_M_prec_kind == _WP_from_arg)
- __prec = __format::__int_from_arg(__ctx.arg(_M_prec));
- return __prec;
- }
- };
- template<typename _Int>
- inline char*
- __put_sign(_Int __i, _Sign __sign, char* __dest) noexcept
- {
- if (__i < 0)
- *__dest = '-';
- else if (__sign == _Sign_plus)
- *__dest = '+';
- else if (__sign == _Sign_space)
- *__dest = ' ';
- else
- ++__dest;
- return __dest;
- }
- // Write STR to OUT (and do so efficiently if OUT is a _Sink_iter).
- template<typename _Out, typename _CharT>
- requires output_iterator<_Out, const _CharT&>
- inline _Out
- __write(_Out __out, basic_string_view<_CharT> __str)
- {
- if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
- {
- if (__str.size())
- __out = __str;
- }
- else
- for (_CharT __c : __str)
- *__out++ = __c;
- return __out;
- }
- // Write STR to OUT with NFILL copies of FILL_CHAR specified by ALIGN.
- // pre: __align != _Align_default
- template<typename _Out, typename _CharT>
- _Out
- __write_padded(_Out __out, basic_string_view<_CharT> __str,
- _Align __align, size_t __nfill, _CharT __fill_char)
- {
- const size_t __buflen = 0x20;
- _CharT __padding_chars[__buflen];
- __padding_chars[0] = _CharT();
- basic_string_view<_CharT> __padding{__padding_chars, __buflen};
- auto __pad = [&__padding] (size_t __n, _Out& __o) {
- if (__n == 0)
- return;
- while (__n > __padding.size())
- {
- __o = __format::__write(std::move(__o), __padding);
- __n -= __padding.size();
- }
- if (__n != 0)
- __o = __format::__write(std::move(__o), __padding.substr(0, __n));
- };
- size_t __l, __r, __max;
- if (__align == _Align_centre)
- {
- __l = __nfill / 2;
- __r = __l + (__nfill & 1);
- __max = __r;
- }
- else if (__align == _Align_right)
- {
- __l = __nfill;
- __r = 0;
- __max = __l;
- }
- else
- {
- __l = 0;
- __r = __nfill;
- __max = __r;
- }
- if (__max < __buflen)
- __padding.remove_suffix(__buflen - __max);
- else
- __max = __buflen;
- char_traits<_CharT>::assign(__padding_chars, __max, __fill_char);
- __pad(__l, __out);
- __out = __format::__write(std::move(__out), __str);
- __pad(__r, __out);
- return __out;
- }
- // Write STR to OUT, with alignment and padding as determined by SPEC.
- // pre: __spec._M_align != _Align_default || __align != _Align_default
- template<typename _CharT, typename _Out>
- _Out
- __write_padded_as_spec(basic_string_view<type_identity_t<_CharT>> __str,
- size_t __estimated_width,
- basic_format_context<_Out, _CharT>& __fc,
- const _Spec<_CharT>& __spec,
- _Align __align = _Align_left)
- {
- size_t __width = __spec._M_get_width(__fc);
- if (__width <= __estimated_width)
- return __format::__write(__fc.out(), __str);
- const size_t __nfill = __width - __estimated_width;
- if (__spec._M_align)
- __align = __spec._M_align;
- return __format::__write_padded(__fc.out(), __str, __align, __nfill,
- __spec._M_fill);
- }
- // A lightweight optional<locale>.
- struct _Optional_locale
- {
- [[__gnu__::__always_inline__]]
- _Optional_locale() : _M_dummy(), _M_hasval(false) { }
- _Optional_locale(const locale& __loc) noexcept
- : _M_loc(__loc), _M_hasval(true)
- { }
- _Optional_locale(const _Optional_locale& __l) noexcept
- : _M_dummy(), _M_hasval(__l._M_hasval)
- {
- if (_M_hasval)
- std::construct_at(&_M_loc, __l._M_loc);
- }
- _Optional_locale&
- operator=(const _Optional_locale& __l) noexcept
- {
- if (_M_hasval)
- {
- if (__l._M_hasval)
- _M_loc = __l._M_loc;
- else
- {
- _M_loc.~locale();
- _M_hasval = false;
- }
- }
- else if (__l._M_hasval)
- {
- std::construct_at(&_M_loc, __l._M_loc);
- _M_hasval = true;
- }
- return *this;
- }
- ~_Optional_locale() { if (_M_hasval) _M_loc.~locale(); }
- _Optional_locale&
- operator=(locale&& __loc) noexcept
- {
- if (_M_hasval)
- _M_loc = std::move(__loc);
- else
- {
- std::construct_at(&_M_loc, std::move(__loc));
- _M_hasval = true;
- }
- return *this;
- }
- const locale&
- value() noexcept
- {
- if (!_M_hasval)
- {
- std::construct_at(&_M_loc);
- _M_hasval = true;
- }
- return _M_loc;
- }
- bool has_value() const noexcept { return _M_hasval; }
- union {
- char _M_dummy = '\0';
- std::locale _M_loc;
- };
- bool _M_hasval = false;
- };
- template<typename _CharT>
- concept __char = same_as<_CharT, char> || same_as<_CharT, wchar_t>;
- template<__char _CharT>
- struct __formatter_str
- {
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- {
- auto __first = __pc.begin();
- const auto __last = __pc.end();
- _Spec<_CharT> __spec{};
- auto __finalize = [this, &__spec] {
- _M_spec = __spec;
- };
- auto __finished = [&] {
- if (__first == __last || *__first == '}')
- {
- __finalize();
- return true;
- }
- return false;
- };
- if (__finished())
- return __first;
- __first = __spec._M_parse_fill_and_align(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_width(__first, __last, __pc);
- if (__finished())
- return __first;
- __first = __spec._M_parse_precision(__first, __last, __pc);
- if (__finished())
- return __first;
- if (*__first == 's')
- ++__first;
- #if __cpp_lib_format_ranges
- else if (*__first == '?')
- {
- __spec._M_type = _Pres_esc;
- ++__first;
- }
- #endif
- if (__finished())
- return __first;
- __format::__failed_to_parse_format_spec();
- }
- template<typename _Out>
- _Out
- format(basic_string_view<_CharT> __s,
- basic_format_context<_Out, _CharT>& __fc) const
- {
- if (_M_spec._M_type == _Pres_esc)
- {
- // TODO: C++23 escaped string presentation
- }
- if (_M_spec._M_width_kind == _WP_none
- && _M_spec._M_prec_kind == _WP_none)
- return __format::__write(__fc.out(), __s);
- size_t __estimated_width = __s.size(); // TODO: Unicode-aware estim.
- if (_M_spec._M_prec_kind != _WP_none)
- {
- size_t __prec = _M_spec._M_get_precision(__fc);
- if (__estimated_width > __prec)
- {
- __s = __s.substr(0, __prec); // TODO: do not split code points
- __estimated_width = __prec;
- }
- }
- return __format::__write_padded_as_spec(__s, __estimated_width,
- __fc, _M_spec);
- }
- #if __cpp_lib_format_ranges
- constexpr void
- set_debug_format() noexcept
- { _M_spec._M_type = _Pres_esc; }
- #endif
- private:
- _Spec<_CharT> _M_spec{};
- };
- template<__char _CharT>
- struct __formatter_int
- {
- // If no presentation type is specified, meaning of "none" depends
- // whether we are formatting an integer or a char or a bool.
- static constexpr _Pres_type _AsInteger = _Pres_d;
- static constexpr _Pres_type _AsBool = _Pres_s;
- static constexpr _Pres_type _AsChar = _Pres_c;
- constexpr typename basic_format_parse_context<_CharT>::iterator
- _M_do_parse(basic_format_parse_context<_CharT>& __pc, _Pres_type __type)
- {
- _Spec<_CharT> __spec{};
- __spec._M_type = __type;
- const auto __last = __pc.end();
- auto __first = __pc.begin();
- auto __finalize = [this, &__spec] {
- _M_spec = __spec;
- };
- auto __finished = [&] {
- if (__first == __last || *__first == '}')
- {
- __finalize();
- return true;
- }
- return false;
- };
- if (__finished())
- return __first;
- __first = __spec._M_parse_fill_and_align(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_sign(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_alternate_form(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_zero_fill(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_width(__first, __last, __pc);
- if (__finished())
- return __first;
- __first = __spec._M_parse_locale(__first, __last);
- if (__finished())
- return __first;
- switch (*__first)
- {
- case 'b':
- __spec._M_type = _Pres_b;
- ++__first;
- break;
- case 'B':
- __spec._M_type = _Pres_B;
- ++__first;
- break;
- case 'c':
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3586. format should not print bool with 'c'
- if (__type != _AsBool)
- {
- __spec._M_type = _Pres_c;
- ++__first;
- }
- break;
- case 'd':
- __spec._M_type = _Pres_d;
- ++__first;
- break;
- case 'o':
- __spec._M_type = _Pres_o;
- ++__first;
- break;
- case 'x':
- __spec._M_type = _Pres_x;
- ++__first;
- break;
- case 'X':
- __spec._M_type = _Pres_X;
- ++__first;
- break;
- case 's':
- if (__type == _AsBool)
- {
- __spec._M_type = _Pres_s; // same value (and meaning) as "none"
- ++__first;
- }
- break;
- #if __cpp_lib_format_ranges
- case '?':
- if (__type == _AsChar)
- {
- __spec._M_type = _Pres_esc;
- ++__first;
- }
- #endif
- break;
- }
- if (__finished())
- return __first;
- __format::__failed_to_parse_format_spec();
- }
- template<typename _Tp>
- constexpr typename basic_format_parse_context<_CharT>::iterator
- _M_parse(basic_format_parse_context<_CharT>& __pc)
- {
- if constexpr (is_same_v<_Tp, bool>)
- {
- auto __end = _M_do_parse(__pc, _AsBool);
- if (_M_spec._M_type == _Pres_s)
- if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill)
- __throw_format_error("format error: format-spec contains "
- "invalid formatting options for "
- "'bool'");
- return __end;
- }
- else if constexpr (__char<_Tp>)
- {
- auto __end = _M_do_parse(__pc, _AsChar);
- if (_M_spec._M_type == _Pres_c || _M_spec._M_type == _Pres_esc)
- if (_M_spec._M_sign || _M_spec._M_alt || _M_spec._M_zero_fill
- /* XXX should be invalid? || _M_spec._M_localized */)
- __throw_format_error("format error: format-spec contains "
- "invalid formatting options for "
- "'charT'");
- return __end;
- }
- else
- return _M_do_parse(__pc, _AsInteger);
- }
- template<typename _Int, typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(_Int __i, basic_format_context<_Out, _CharT>& __fc) const
- {
- if (_M_spec._M_type == _Pres_c)
- return _M_format_character(_S_to_character(__i), __fc);
- char __buf[sizeof(_Int) * __CHAR_BIT__ + 3];
- to_chars_result __res{};
- string_view __base_prefix;
- make_unsigned_t<_Int> __u;
- if (__i < 0)
- __u = -static_cast<make_unsigned_t<_Int>>(__i);
- else
- __u = __i;
- char* __start = __buf + 3;
- char* const __end = __buf + sizeof(__buf);
- char* const __start_digits = __start;
- switch (_M_spec._M_type)
- {
- case _Pres_b:
- case _Pres_B:
- __base_prefix = _M_spec._M_type == _Pres_b ? "0b" : "0B";
- __res = to_chars(__start, __end, __u, 2);
- break;
- #if 0
- case _Pres_c:
- return _M_format_character(_S_to_character(__i), __fc);
- #endif
- case _Pres_none:
- // Should not reach here with _Pres_none for bool or charT, so:
- [[fallthrough]];
- case _Pres_d:
- __res = to_chars(__start, __end, __u, 10);
- break;
- case _Pres_o:
- if (__i != 0)
- __base_prefix = "0";
- __res = to_chars(__start, __end, __u, 8);
- break;
- case _Pres_x:
- case _Pres_X:
- __base_prefix = _M_spec._M_type == _Pres_x ? "0x" : "0X";
- __res = to_chars(__start, __end, __u, 16);
- if (_M_spec._M_type == _Pres_X)
- for (auto __p = __start; __p != __res.ptr; ++__p)
- #if __has_builtin(__builtin_toupper)
- *__p = __builtin_toupper(*__p);
- #else
- *__p = std::toupper(*__p);
- #endif
- break;
- default:
- __builtin_unreachable();
- }
- if (_M_spec._M_alt && __base_prefix.size())
- {
- __start -= __base_prefix.size();
- __builtin_memcpy(__start, __base_prefix.data(),
- __base_prefix.size());
- }
- __start = __format::__put_sign(__i, _M_spec._M_sign, __start - 1);
- return _M_format_int(string_view(__start, __res.ptr - __start),
- __start_digits - __start, __fc);
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(bool __i, basic_format_context<_Out, _CharT>& __fc) const
- {
- if (_M_spec._M_type == _Pres_c)
- return _M_format_character(static_cast<unsigned char>(__i), __fc);
- if (_M_spec._M_type != _Pres_s)
- return format(static_cast<unsigned char>(__i), __fc);
- basic_string<_CharT> __s;
- size_t __est_width;
- if (_M_spec._M_localized) [[unlikely]]
- {
- auto& __np = std::use_facet<numpunct<_CharT>>(__fc.locale());
- __s = __i ? __np.truename() : __np.falsename();
- __est_width = __s.size(); // TODO Unicode-aware estimate
- }
- else
- {
- if constexpr (is_same_v<char, _CharT>)
- __s = __i ? "true" : "false";
- else
- __s = __i ? L"true" : L"false";
- __est_width = __s.size();
- }
- return __format::__write_padded_as_spec(__s, __est_width, __fc,
- _M_spec);
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- _M_format_character(_CharT __c,
- basic_format_context<_Out, _CharT>& __fc) const
- {
- return __format::__write_padded_as_spec({&__c, 1u}, 1, __fc, _M_spec);
- }
- template<typename _Int>
- static _CharT
- _S_to_character(_Int __i)
- {
- using _Traits = __gnu_cxx::__int_traits<_CharT>;
- if constexpr (is_signed_v<_Int> == is_signed_v<_CharT>)
- {
- if (_Traits::__min <= __i && __i <= _Traits::__max)
- return static_cast<_CharT>(__i);
- }
- else if constexpr (is_signed_v<_Int>)
- {
- if (__i >= 0 && make_unsigned_t<_Int>(__i) <= _Traits::__max)
- return static_cast<_CharT>(__i);
- }
- else if (__i <= make_unsigned_t<_CharT>(_Traits::__max))
- return static_cast<_CharT>(__i);
- __throw_format_error("format error: integer not representable as "
- "character");
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- _M_format_int(string_view __narrow_str, size_t __prefix_len,
- basic_format_context<_Out, _CharT>& __fc) const
- {
- size_t __width = _M_spec._M_get_width(__fc);
- _Optional_locale __loc;
- basic_string_view<_CharT> __str;
- if constexpr (is_same_v<char, _CharT>)
- __str = __narrow_str;
- else
- {
- __loc = __fc.locale();
- auto& __ct = use_facet<ctype<_CharT>>(__loc.value());
- size_t __n = __narrow_str.size();
- auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
- __ct.widen(__narrow_str.data(), __narrow_str.data() + __n, __p);
- __str = {__p, __n};
- }
- if (_M_spec._M_localized)
- {
- if constexpr (is_same_v<char, _CharT>)
- __loc = __fc.locale();
- const auto& __l = __loc.value();
- if (__l.name() != "C")
- {
- auto& __np = use_facet<numpunct<_CharT>>(__l);
- string __grp = __np.grouping();
- if (!__grp.empty())
- {
- size_t __n = __str.size() - __prefix_len;
- auto __p = (_CharT*)__builtin_alloca(2 * __n
- * sizeof(_CharT)
- + __prefix_len);
- auto __s = __str.data();
- char_traits<_CharT>::copy(__p, __s, __prefix_len);
- __s += __prefix_len;
- auto __end = std::__add_grouping(__p + __prefix_len,
- __np.thousands_sep(),
- __grp.data(),
- __grp.size(),
- __s, __s + __n);
- __str = {__p, size_t(__end - __p)};
- }
- }
- }
- if (__width <= __str.size())
- return __format::__write(__fc.out(), __str);
- _CharT __fill_char = _M_spec._M_fill;
- _Align __align = _M_spec._M_align;
- size_t __nfill = __width - __str.size();
- auto __out = __fc.out();
- if (__align == _Align_default)
- {
- __align = _Align_right;
- if (_M_spec._M_zero_fill)
- {
- __fill_char = _CharT('0');
- // Write sign and base prefix before zero filling.
- if (__prefix_len != 0)
- {
- __out = __format::__write(std::move(__out),
- __str.substr(0, __prefix_len));
- __str.remove_prefix(__prefix_len);
- }
- }
- else
- __fill_char = _CharT(' ');
- }
- return __format::__write_padded(std::move(__out), __str,
- __align, __nfill, __fill_char);
- }
- #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
- template<typename _Tp>
- using make_unsigned_t
- = typename __conditional_t<(sizeof(_Tp) <= sizeof(long long)),
- std::make_unsigned<_Tp>,
- type_identity<unsigned __int128>>::type;
- // std::to_chars is not overloaded for int128 in strict mode.
- template<typename _Int>
- static to_chars_result
- to_chars(char* __first, char* __last, _Int __value, int __base)
- { return std::__to_chars_i<_Int>(__first, __last, __value, __base); }
- #endif
- _Spec<_CharT> _M_spec{};
- };
- // Decide how 128-bit floating-point types should be formatted (or not).
- // When supported, the typedef __format::__float128_t is the type that
- // format arguments should be converted to for storage in basic_format_arg.
- // Define the macro _GLIBCXX_FORMAT_F128 to say they're supported.
- // _GLIBCXX_FORMAT_F128=1 means __float128, _Float128 etc. will be formatted
- // by converting them to long double (or __ieee128 for powerpc64le).
- // _GLIBCXX_FORMAT_F128=2 means basic_format_arg needs to enable explicit
- // support for _Float128, rather than formatting it as another type.
- #undef _GLIBCXX_FORMAT_F128
- #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- // Format 128-bit floating-point types using __ieee128.
- using __float128_t = __ieee128;
- # define _GLIBCXX_FORMAT_F128 1
- #ifdef __LONG_DOUBLE_IEEE128__
- // These overloads exist in the library, but are not declared.
- // Make them available as std::__format::to_chars.
- to_chars_result
- to_chars(char*, char*, __ibm128) noexcept
- __asm("_ZSt8to_charsPcS_e");
- to_chars_result
- to_chars(char*, char*, __ibm128, chars_format) noexcept
- __asm("_ZSt8to_charsPcS_eSt12chars_format");
- to_chars_result
- to_chars(char*, char*, __ibm128, chars_format, int) noexcept
- __asm("_ZSt8to_charsPcS_eSt12chars_formati");
- #elif __cplusplus == 202002L
- to_chars_result
- to_chars(char*, char*, __ieee128) noexcept
- __asm("_ZSt8to_charsPcS_u9__ieee128");
- to_chars_result
- to_chars(char*, char*, __ieee128, chars_format) noexcept
- __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_format");
- to_chars_result
- to_chars(char*, char*, __ieee128, chars_format, int) noexcept
- __asm("_ZSt8to_charsPcS_u9__ieee128St12chars_formati");
- #endif
- #elif defined _GLIBCXX_LDOUBLE_IS_IEEE_BINARY128
- // Format 128-bit floating-point types using long double.
- using __float128_t = long double;
- # define _GLIBCXX_FORMAT_F128 1
- #elif __FLT128_DIG__ && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
- // Format 128-bit floating-point types using _Float128.
- using __float128_t = _Float128;
- # define _GLIBCXX_FORMAT_F128 2
- # if __cplusplus == 202002L
- // These overloads exist in the library, but are not declared for C++20.
- // Make them available as std::__format::to_chars.
- to_chars_result
- to_chars(char*, char*, _Float128) noexcept
- # if _GLIBCXX_INLINE_VERSION
- __asm("_ZNSt3__88to_charsEPcS0_DF128_");
- # else
- __asm("_ZSt8to_charsPcS_DF128_");
- # endif
- to_chars_result
- to_chars(char*, char*, _Float128, chars_format) noexcept
- # if _GLIBCXX_INLINE_VERSION
- __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatE");
- # else
- __asm("_ZSt8to_charsPcS_DF128_St12chars_format");
- # endif
- to_chars_result
- to_chars(char*, char*, _Float128, chars_format, int) noexcept
- # if _GLIBCXX_INLINE_VERSION
- __asm("_ZNSt3__88to_charsEPcS0_DF128_NS_12chars_formatEi");
- # else
- __asm("_ZSt8to_charsPcS_DF128_St12chars_formati");
- # endif
- # endif
- #endif
- using std::to_chars;
- // We can format a floating-point type iff it is usable with to_chars.
- template<typename _Tp>
- concept __formattable_float = requires (_Tp __t, char* __p)
- { __format::to_chars(__p, __p, __t, chars_format::scientific, 6); };
- template<__char _CharT>
- struct __formatter_fp
- {
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- {
- _Spec<_CharT> __spec{};
- const auto __last = __pc.end();
- auto __first = __pc.begin();
- auto __finalize = [this, &__spec] {
- _M_spec = __spec;
- };
- auto __finished = [&] {
- if (__first == __last || *__first == '}')
- {
- __finalize();
- return true;
- }
- return false;
- };
- if (__finished())
- return __first;
- __first = __spec._M_parse_fill_and_align(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_sign(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_alternate_form(__first, __last);
- if (__finished())
- return __first;
- __first = __spec._M_parse_zero_fill(__first, __last);
- if (__finished())
- return __first;
- if (__first[0] != '.')
- {
- __first = __spec._M_parse_width(__first, __last, __pc);
- if (__finished())
- return __first;
- }
- __first = __spec._M_parse_precision(__first, __last, __pc);
- if (__finished())
- return __first;
- __first = __spec._M_parse_locale(__first, __last);
- if (__finished())
- return __first;
- switch (*__first)
- {
- case 'a':
- __spec._M_type = _Pres_a;
- ++__first;
- break;
- case 'A':
- __spec._M_type = _Pres_A;
- ++__first;
- break;
- case 'e':
- __spec._M_type = _Pres_e;
- ++__first;
- break;
- case 'E':
- __spec._M_type = _Pres_E;
- ++__first;
- break;
- case 'f':
- __spec._M_type = _Pres_f;
- ++__first;
- break;
- case 'F':
- __spec._M_type = _Pres_F;
- ++__first;
- break;
- case 'g':
- __spec._M_type = _Pres_g;
- ++__first;
- break;
- case 'G':
- __spec._M_type = _Pres_G;
- ++__first;
- break;
- }
- if (__finished())
- return __first;
- __format::__failed_to_parse_format_spec();
- }
- template<typename _Fp, typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(_Fp __v, basic_format_context<_Out, _CharT>& __fc) const
- {
- std::string __dynbuf;
- char __buf[128];
- to_chars_result __res{};
- size_t __prec = 6;
- bool __use_prec = _M_spec._M_prec_kind != _WP_none;
- if (__use_prec)
- __prec = _M_spec._M_get_precision(__fc);
- char* __start = __buf + 1; // reserve space for sign
- char* __end = __buf + sizeof(__buf);
- chars_format __fmt{};
- bool __upper = false;
- bool __trailing_zeros = false;
- char __expc = 'e';
- switch (_M_spec._M_type)
- {
- case _Pres_A:
- __upper = true;
- __expc = 'P';
- [[fallthrough]];
- case _Pres_a:
- if (_M_spec._M_type != _Pres_A)
- __expc = 'p';
- __fmt = chars_format::hex;
- break;
- case _Pres_E:
- __upper = true;
- __expc = 'E';
- [[fallthrough]];
- case _Pres_e:
- __use_prec = true;
- __fmt = chars_format::scientific;
- break;
- case _Pres_F:
- __upper = true;
- [[fallthrough]];
- case _Pres_f:
- __use_prec = true;
- __fmt = chars_format::fixed;
- break;
- case _Pres_G:
- __upper = true;
- __expc = 'E';
- [[fallthrough]];
- case _Pres_g:
- __trailing_zeros = true;
- __use_prec = true;
- __fmt = chars_format::general;
- break;
- case _Pres_none:
- if (__use_prec)
- __fmt = chars_format::general;
- break;
- default:
- __builtin_unreachable();
- }
- // Write value into buffer using std::to_chars.
- auto __to_chars = [&](char* __b, char* __e) {
- if (__use_prec)
- return __format::to_chars(__b, __e, __v, __fmt, __prec);
- else if (__fmt != chars_format{})
- return __format::to_chars(__b, __e, __v, __fmt);
- else
- return __format::to_chars(__b, __e, __v);
- };
- // First try using stack buffer.
- __res = __to_chars(__start, __end);
- if (__builtin_expect(__res.ec == errc::value_too_large, 0))
- {
- // If the buffer is too small it's probably because of a large
- // precision, or a very large value in fixed format.
- size_t __guess = 8 + __prec;
- if (__fmt == chars_format::fixed) // +ddd.prec
- {
- if constexpr (is_same_v<_Fp, float> || is_same_v<_Fp, double>
- || is_same_v<_Fp, long double>)
- {
- // The number of digits to the left of the decimal point
- // is floor(log10(max(abs(__v),1)))+1
- int __exp{};
- if constexpr (is_same_v<_Fp, float>)
- __builtin_frexpf(__v, &__exp);
- else if constexpr (is_same_v<_Fp, double>)
- __builtin_frexp(__v, &__exp);
- else if constexpr (is_same_v<_Fp, long double>)
- __builtin_frexpl(__v, &__exp);
- if (__exp > 0)
- __guess += 1U + __exp * 4004U / 13301U; // log10(2) approx.
- }
- else
- __guess += numeric_limits<_Fp>::max_exponent10;
- }
- if (__guess <= sizeof(__buf)) [[unlikely]]
- __guess = sizeof(__buf) * 2;
- __dynbuf.reserve(__guess);
- do
- {
- auto __overwrite = [&__to_chars, &__res] (char* __p, size_t __n)
- {
- __res = __to_chars(__p + 1, __p + __n - 1);
- return __res.ec == errc{} ? __res.ptr - __p : 0;
- };
- _S_resize_and_overwrite(__dynbuf, __dynbuf.capacity() * 2,
- __overwrite);
- __start = __dynbuf.data() + 1; // reserve space for sign
- __end = __dynbuf.data() + __dynbuf.size();
- }
- while (__builtin_expect(__res.ec == errc::value_too_large, 0));
- }
- // Use uppercase for 'A', 'E', and 'G' formats.
- if (__upper)
- {
- for (char* __p = __start; __p != __res.ptr; ++__p)
- *__p = std::toupper(*__p);
- }
- bool __have_sign = true;
- // Add sign for non-negative values.
- if (!__builtin_signbit(__v))
- {
- if (_M_spec._M_sign == _Sign_plus)
- *--__start = '+';
- else if (_M_spec._M_sign == _Sign_space)
- *--__start = ' ';
- else
- __have_sign = false;
- }
- string_view __narrow_str(__start, __res.ptr - __start);
- // Use alternate form. Ensure decimal point is always present,
- // and add trailing zeros (up to precision) for g and G forms.
- if (_M_spec._M_alt && __builtin_isfinite(__v))
- {
- string_view __s = __narrow_str;
- size_t __sigfigs; // Number of significant figures.
- size_t __z = 0; // Number of trailing zeros to add.
- size_t __p; // Position of the exponent character (if any).
- size_t __d = __s.find('.'); // Position of decimal point.
- if (__d != __s.npos) // Found decimal point.
- {
- __p = __s.find(__expc, __d + 1);
- if (__p == __s.npos)
- __p = __s.size();
- // If presentation type is g or G we might need to add zeros.
- if (__trailing_zeros)
- {
- // Find number of digits after first significant figure.
- if (__s[__have_sign] != '0')
- // A string like "D.D" or "-D.DDD"
- __sigfigs = __p - __have_sign - 1;
- else
- // A string like "0.D" or "-0.0DD".
- // Safe to assume there is a non-zero digit, because
- // otherwise there would be no decimal point.
- __sigfigs = __p - __s.find_first_not_of('0', __d + 1);
- }
- }
- else // No decimal point, we need to insert one.
- {
- __p = __s.find(__expc); // Find the exponent, if present.
- if (__p == __s.npos)
- __p = __s.size();
- __d = __p; // Position where '.' should be inserted.
- __sigfigs = __d - __have_sign;
- }
- if (__trailing_zeros && __prec != 0)
- {
- // For g and G presentation types std::to_chars produces
- // no more than prec significant figures. Insert this many
- // zeros so the result has exactly prec significant figures.
- __z = __prec - __sigfigs;
- }
- if (size_t __extras = int(__d == __p) + __z) // How many to add.
- {
- if (__dynbuf.empty() && __extras <= size_t(__end - __res.ptr))
- {
- // The stack buffer is large enough for the result.
- // Move exponent to make space for extra chars.
- __builtin_memmove(__start + __p + __extras,
- __start + __p,
- __s.size() - __p);
- if (__d == __p)
- __start[__p++] = '.';
- __builtin_memset(__start + __p, '0', __z);
- __narrow_str = {__s.data(), __s.size() + __extras};
- }
- else // Need to switch to the dynamic buffer.
- {
- __dynbuf.reserve(__s.size() + __extras);
- if (__dynbuf.empty())
- {
- __dynbuf = __s.substr(0, __p);
- if (__d == __p)
- __dynbuf += '.';
- if (__z)
- __dynbuf.append(__z, '0');
- __dynbuf.append(__s.substr(__p));
- }
- else
- {
- __dynbuf.insert(__p, __extras, '0');
- if (__d == __p)
- __dynbuf[__p] = '.';
- }
- __narrow_str = __dynbuf;
- }
- }
- }
- // TODO move everything below to a new member function that
- // doesn't depend on _Fp type.
- _Optional_locale __loc;
- basic_string<_CharT> __wstr;
- basic_string_view<_CharT> __str;
- if constexpr (is_same_v<_CharT, char>)
- __str = __narrow_str;
- else
- {
- __loc = __fc.locale();
- auto& __ct = use_facet<ctype<_CharT>>(__loc.value());
- const char* __data = __narrow_str.data();
- auto __overwrite = [&__data, &__ct](_CharT* __p, size_t __n)
- {
- __ct.widen(__data, __data + __n, __p);
- return __n;
- };
- _S_resize_and_overwrite(__wstr, __narrow_str.size(), __overwrite);
- __str = __wstr;
- }
- if (_M_spec._M_localized && __builtin_isfinite(__v))
- {
- if constexpr (is_same_v<char, _CharT>)
- __wstr = _M_localize(__str, __expc, __fc.locale());
- else
- __wstr = _M_localize(__str, __expc, __loc.value());
- if (!__wstr.empty())
- __str = __wstr;
- }
- size_t __width = _M_spec._M_get_width(__fc);
- if (__width <= __str.size())
- return __format::__write(__fc.out(), __str);
- _CharT __fill_char = _M_spec._M_fill;
- _Align __align = _M_spec._M_align;
- size_t __nfill = __width - __str.size();
- auto __out = __fc.out();
- if (__align == _Align_default)
- {
- __align = _Align_right;
- if (_M_spec._M_zero_fill && __builtin_isfinite(__v))
- {
- __fill_char = _CharT('0');
- // Write sign before zero filling.
- if (!__format::__is_xdigit(__narrow_str[0]))
- {
- *__out++ = __str[0];
- __str.remove_prefix(1);
- }
- }
- else
- __fill_char = _CharT(' ');
- }
- return __format::__write_padded(std::move(__out), __str,
- __align, __nfill, __fill_char);
- }
- // Locale-specific format.
- basic_string<_CharT>
- _M_localize(basic_string_view<_CharT> __str, char __expc,
- const locale& __loc) const
- {
- basic_string<_CharT> __lstr;
- if (__loc == locale::classic())
- return __lstr; // Nothing to do.
- const auto& __np = use_facet<numpunct<_CharT>>(__loc);
- const _CharT __point = __np.decimal_point();
- const string __grp = __np.grouping();
- _CharT __dot, __exp;
- if constexpr (is_same_v<_CharT, char>)
- {
- __dot = '.';
- __exp = __expc;
- }
- else
- {
- const auto& __ct = use_facet<ctype<_CharT>>(__loc);
- __dot = __ct.widen('.');
- __exp = __ct.widen(__expc);
- }
- if (__grp.empty() && __point == __dot)
- return __lstr; // Locale uses '.' and no grouping.
- size_t __d = __str.find(__dot);
- size_t __e = min(__d, __str.find(__exp));
- if (__e == __str.npos)
- __e = __str.size();
- const size_t __r = __str.size() - __e;
- auto __overwrite = [&](_CharT* __p, size_t) {
- auto __end = std::__add_grouping(__p, __np.thousands_sep(),
- __grp.data(), __grp.size(),
- __str.data(), __str.data() + __e);
- if (__r)
- {
- if (__d != __str.npos)
- {
- *__end = __point;
- ++__end;
- ++__e;
- }
- if (__r > 1)
- __end += __str.copy(__end, __str.npos, __e);
- }
- return (__end - __p);
- };
- _S_resize_and_overwrite(__lstr, __e * 2 + __r, __overwrite);
- return __lstr;
- }
- template<typename _Ch, typename _Func>
- static void
- _S_resize_and_overwrite(basic_string<_Ch>& __str, size_t __n, _Func __f)
- {
- #if __cpp_lib_string_resize_and_overwrite
- __str.resize_and_overwrite(__n, __f);
- #else
- __str.resize(__n);
- __str.resize(__f(__str.data(), __n));
- #endif
- }
- _Spec<_CharT> _M_spec{};
- };
- } // namespace __format
- /// @endcond
- // Format a character.
- template<__format::__char _CharT>
- struct formatter<_CharT, _CharT>
- {
- formatter() = default;
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- {
- return _M_f.template _M_parse<_CharT>(__pc);
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(_CharT __u, basic_format_context<_Out, _CharT>& __fc) const
- {
- if (_M_f._M_spec._M_type == __format::_Pres_none
- || _M_f._M_spec._M_type == __format::_Pres_c)
- return _M_f._M_format_character(__u, __fc);
- else if (_M_f._M_spec._M_type == __format::_Pres_esc)
- {
- // TODO
- return __fc.out();
- }
- else
- return _M_f.format(static_cast<make_unsigned_t<_CharT>>(__u), __fc);
- }
- #if __cpp_lib_format_ranges
- constexpr void
- set_debug_format() noexcept
- { _M_f._M_spec._M_type = __format::_Pres_esc; }
- #endif
- private:
- __format::__formatter_int<_CharT> _M_f;
- };
- // Format a char value for wide character output.
- template<>
- struct formatter<char, wchar_t>
- {
- formatter() = default;
- constexpr typename basic_format_parse_context<wchar_t>::iterator
- parse(basic_format_parse_context<wchar_t>& __pc)
- {
- return _M_f._M_parse<char>(__pc);
- }
- template<typename _Out>
- typename basic_format_context<_Out, wchar_t>::iterator
- format(char __u, basic_format_context<_Out, wchar_t>& __fc) const
- {
- if (_M_f._M_spec._M_type == __format::_Pres_none
- || _M_f._M_spec._M_type == __format::_Pres_c)
- return _M_f._M_format_character(__u, __fc);
- else if (_M_f._M_spec._M_type == __format::_Pres_esc)
- {
- // TODO
- return __fc.out();
- }
- else
- return _M_f.format(static_cast<unsigned char>(__u), __fc);
- }
- #if __cpp_lib_format_ranges
- constexpr void
- set_debug_format() noexcept
- { _M_f._M_spec._M_type = __format::_Pres_esc; }
- #endif
- private:
- __format::__formatter_int<wchar_t> _M_f;
- };
- /** Format a string.
- * @{
- */
- template<__format::__char _CharT>
- struct formatter<_CharT*, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- [[__gnu__::__nonnull__]]
- typename basic_format_context<_Out, _CharT>::iterator
- format(_CharT* __u, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(__u, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<_CharT> _M_f;
- };
- template<__format::__char _CharT>
- struct formatter<const _CharT*, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- [[__gnu__::__nonnull__]]
- typename basic_format_context<_Out, _CharT>::iterator
- format(const _CharT* __u,
- basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(__u, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<_CharT> _M_f;
- };
- template<__format::__char _CharT, size_t _Nm>
- struct formatter<_CharT[_Nm], _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const _CharT (&__u)[_Nm],
- basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format({__u, _Nm}, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<_CharT> _M_f;
- };
- template<typename _Traits, typename _Alloc>
- struct formatter<basic_string<char, _Traits, _Alloc>, char>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<char>::iterator
- parse(basic_format_parse_context<char>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, char>::iterator
- format(const basic_string<char, _Traits, _Alloc>& __u,
- basic_format_context<_Out, char>& __fc) const
- { return _M_f.format(__u, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<char> _M_f;
- };
- template<typename _Traits, typename _Alloc>
- struct formatter<basic_string<wchar_t, _Traits, _Alloc>, wchar_t>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<wchar_t>::iterator
- parse(basic_format_parse_context<wchar_t>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, wchar_t>::iterator
- format(const basic_string<wchar_t, _Traits, _Alloc>& __u,
- basic_format_context<_Out, wchar_t>& __fc) const
- { return _M_f.format(__u, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<wchar_t> _M_f;
- };
- template<typename _Traits>
- struct formatter<basic_string_view<char, _Traits>, char>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<char>::iterator
- parse(basic_format_parse_context<char>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, char>::iterator
- format(basic_string_view<char, _Traits> __u,
- basic_format_context<_Out, char>& __fc) const
- { return _M_f.format(__u, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<char> _M_f;
- };
- template<typename _Traits>
- struct formatter<basic_string_view<wchar_t, _Traits>, wchar_t>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<wchar_t>::iterator
- parse(basic_format_parse_context<wchar_t>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, wchar_t>::iterator
- format(basic_string_view<wchar_t, _Traits> __u,
- basic_format_context<_Out, wchar_t>& __fc) const
- { return _M_f.format(__u, __fc); }
- #if __cpp_lib_format_ranges
- constexpr void set_debug_format() noexcept { _M_f.set_debug_format(); }
- #endif
- private:
- __format::__formatter_str<wchar_t> _M_f;
- };
- /// @}
- /// Format an integer.
- template<integral _Tp, __format::__char _CharT>
- requires (!__is_one_of<_Tp, char, wchar_t, char16_t, char32_t>::value)
- struct formatter<_Tp, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- {
- return _M_f.template _M_parse<_Tp>(__pc);
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(__u, __fc); }
- private:
- __format::__formatter_int<_CharT> _M_f;
- };
- #if defined __SIZEOF_INT128__ && defined __STRICT_ANSI__
- template<typename _Tp, __format::__char _CharT>
- requires (__is_one_of<_Tp, __int128, unsigned __int128>::value)
- struct formatter<_Tp, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- {
- return _M_f.template _M_parse<_Tp>(__pc);
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(__u, __fc); }
- private:
- __format::__formatter_int<_CharT> _M_f;
- };
- #endif
- /// Format a floating-point value.
- template<__format::__formattable_float _Tp, __format::__char _CharT>
- struct formatter<_Tp, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(_Tp __u, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(__u, __fc); }
- private:
- __format::__formatter_fp<_CharT> _M_f;
- };
- /** Format a pointer.
- * @{
- */
- template<__format::__char _CharT>
- struct formatter<const void*, _CharT>
- {
- formatter() = default;
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- {
- __format::_Spec<_CharT> __spec{};
- const auto __last = __pc.end();
- auto __first = __pc.begin();
- auto __finalize = [this, &__spec] {
- _M_spec = __spec;
- };
- auto __finished = [&] {
- if (__first == __last || *__first == '}')
- {
- __finalize();
- return true;
- }
- return false;
- };
- if (__finished())
- return __first;
- __first = __spec._M_parse_fill_and_align(__first, __last);
- if (__finished())
- return __first;
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // P2510R3 Formatting pointers
- #if __cplusplus > 202302L || ! defined __STRICT_ANSI__
- #define _GLIBCXX_P2518R3 1
- #else
- #define _GLIBCXX_P2518R3 0
- #endif
- #if _GLIBCXX_P2518R3
- __first = __spec._M_parse_zero_fill(__first, __last);
- if (__finished())
- return __first;
- #endif
- __first = __spec._M_parse_width(__first, __last, __pc);
- if (__first != __last)
- {
- if (*__first == 'p')
- ++__first;
- #if _GLIBCXX_P2518R3
- else if (*__first == 'P')
- {
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // P2510R3 Formatting pointers
- __spec._M_type = __format::_Pres_P;
- ++__first;
- }
- #endif
- }
- if (__finished())
- return __first;
- __format::__failed_to_parse_format_spec();
- }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
- {
- auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
- char __buf[2 + sizeof(__v) * 2];
- auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
- __u, 16);
- int __n = __ptr - __buf;
- __buf[0] = '0';
- __buf[1] = 'x';
- #if _GLIBCXX_P2518R3
- if (_M_spec._M_type == __format::_Pres_P)
- {
- __buf[1] = 'X';
- for (auto __p = __buf + 2; __p != __ptr; ++__p)
- #if __has_builtin(__builtin_toupper)
- *__p = __builtin_toupper(*__p);
- #else
- *__p = std::toupper(*__p);
- #endif
- }
- #endif
- basic_string_view<_CharT> __str;
- if constexpr (is_same_v<_CharT, char>)
- __str = string_view(__buf, __n);
- else
- {
- const std::locale& __loc = __fc.locale();
- auto& __ct = use_facet<ctype<_CharT>>(__loc);
- auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
- __ct.widen(__buf, __buf + __n, __p);
- __str = wstring_view(__p, __n);
- }
- #if _GLIBCXX_P2518R3
- if (_M_spec._M_zero_fill)
- {
- size_t __width = _M_spec._M_get_width(__fc);
- if (__width <= __str.size())
- return __format::__write(__fc.out(), __str);
- auto __out = __fc.out();
- // Write "0x" or "0X" prefix before zero-filling.
- __out = __format::__write(std::move(__out), __str.substr(0, 2));
- __str.remove_prefix(2);
- size_t __nfill = __width - __n;
- return __format::__write_padded(std::move(__out), __str,
- __format::_Align_right,
- __nfill, _CharT('0'));
- }
- #endif
- return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
- __format::_Align_right);
- }
- private:
- __format::_Spec<_CharT> _M_spec{};
- };
- template<__format::__char _CharT>
- struct formatter<void*, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(void* __v, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(__v, __fc); }
- private:
- formatter<const void*, _CharT> _M_f;
- };
- template<__format::__char _CharT>
- struct formatter<nullptr_t, _CharT>
- {
- formatter() = default;
- [[__gnu__::__always_inline__]]
- constexpr typename basic_format_parse_context<_CharT>::iterator
- parse(basic_format_parse_context<_CharT>& __pc)
- { return _M_f.parse(__pc); }
- template<typename _Out>
- typename basic_format_context<_Out, _CharT>::iterator
- format(nullptr_t, basic_format_context<_Out, _CharT>& __fc) const
- { return _M_f.format(nullptr, __fc); }
- private:
- formatter<const void*, _CharT> _M_f;
- };
- /// @}
- /// @cond undocumented
- namespace __format
- {
- template<typename _Tp, typename _Context,
- typename _Formatter
- = typename _Context::template formatter_type<remove_const_t<_Tp>>,
- typename _ParseContext
- = basic_format_parse_context<typename _Context::char_type>>
- concept __parsable_with
- = semiregular<_Formatter>
- && requires (_Formatter __f, _ParseContext __pc)
- {
- { __f.parse(__pc) } -> same_as<typename _ParseContext::iterator>;
- };
- template<typename _Tp, typename _Context,
- typename _Formatter
- = typename _Context::template formatter_type<remove_const_t<_Tp>>,
- typename _ParseContext
- = basic_format_parse_context<typename _Context::char_type>>
- concept __formattable_with
- = semiregular<_Formatter>
- && requires (const _Formatter __cf, _Tp&& __t, _Context __fc)
- {
- { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
- };
- // An unspecified output iterator type used in the `formattable` concept.
- template<typename _CharT>
- using _Iter_for = back_insert_iterator<basic_string<_CharT>>;
- template<typename _Tp, typename _CharT,
- typename _Context = basic_format_context<_Iter_for<_CharT>, _CharT>>
- concept __formattable_impl
- = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>;
- } // namespace __format
- /// @endcond
- #if __cplusplus > 202002L
- // [format.formattable], concept formattable
- template<typename _Tp, typename _CharT>
- concept formattable
- = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>;
- #endif
- #if __cpp_lib_format_ranges
- /// @cond undocumented
- namespace __format
- {
- template<typename _Rg, typename _CharT>
- concept __const_formattable_range
- = ranges::input_range<const _Rg>
- && formattable<ranges::range_reference_t<const _Rg>, _CharT>;
- template<typename _Rg, typename _CharT>
- using __maybe_const_range
- = conditional_t<__const_formattable_range<_Rg, _CharT>, const _Rg, _Rg>;
- } // namespace __format
- /// @endcond
- #endif // format_ranges
- /// An iterator after the last character written, and the number of
- /// characters that would have been written.
- template<typename _Out>
- struct format_to_n_result
- {
- _Out out;
- iter_difference_t<_Out> size;
- };
- /// @cond undocumented
- namespace __format
- {
- template<typename _CharT>
- class _Sink_iter
- {
- _Sink<_CharT>* _M_sink = nullptr;
- public:
- using iterator_category = output_iterator_tag;
- using value_type = void;
- using difference_type = ptrdiff_t;
- using pointer = void;
- using reference = void;
- _Sink_iter() = default;
- _Sink_iter(const _Sink_iter&) = default;
- _Sink_iter& operator=(const _Sink_iter&) = default;
- [[__gnu__::__always_inline__]]
- explicit constexpr
- _Sink_iter(_Sink<_CharT>& __sink) : _M_sink(std::addressof(__sink)) { }
- [[__gnu__::__always_inline__]]
- constexpr _Sink_iter&
- operator=(_CharT __c)
- {
- _M_sink->_M_write(__c);
- return *this;
- }
- [[__gnu__::__always_inline__]]
- constexpr _Sink_iter&
- operator=(basic_string_view<_CharT> __s)
- {
- _M_sink->_M_write(__s);
- return *this;
- }
- [[__gnu__::__always_inline__]]
- constexpr _Sink_iter&
- operator*() { return *this; }
- [[__gnu__::__always_inline__]]
- constexpr _Sink_iter&
- operator++() { return *this; }
- [[__gnu__::__always_inline__]]
- constexpr _Sink_iter
- operator++(int) { return *this; }
- };
- // Abstract base class for type-erased character sinks.
- // All formatting and output is done via this type's iterator,
- // to reduce the number of different template instantiations.
- template<typename _CharT>
- class _Sink
- {
- friend class _Sink_iter<_CharT>;
- span<_CharT> _M_span;
- typename span<_CharT>::iterator _M_next;
- // Called when the span is full, to make more space available.
- // Precondition: _M_next != _M_span.begin()
- // Postcondition: _M_next != _M_span.end()
- virtual void _M_overflow() = 0;
- protected:
- // Precondition: __span.size() != 0
- [[__gnu__::__always_inline__]]
- explicit constexpr
- _Sink(span<_CharT> __span) noexcept
- : _M_span(__span), _M_next(__span.begin())
- { }
- // The portion of the span that has been written to.
- [[__gnu__::__always_inline__]]
- span<_CharT>
- _M_used() const noexcept
- { return _M_span.first(_M_next - _M_span.begin()); }
- // The portion of the span that has not been written to.
- [[__gnu__::__always_inline__]]
- constexpr span<_CharT>
- _M_unused() const noexcept
- { return _M_span.subspan(_M_next - _M_span.begin()); }
- // Use the start of the span as the next write position.
- [[__gnu__::__always_inline__]]
- constexpr void
- _M_rewind() noexcept
- { _M_next = _M_span.begin(); }
- // Replace the current output range.
- void
- _M_reset(span<_CharT> __s, size_t __pos = 0) noexcept
- {
- _M_span = __s;
- _M_next = __s.begin() + __pos;
- }
- // Called by the iterator for *it++ = c
- constexpr void
- _M_write(_CharT __c)
- {
- *_M_next++ = __c;
- if (_M_next - _M_span.begin() == std::ssize(_M_span)) [[unlikely]]
- _M_overflow();
- }
- constexpr void
- _M_write(basic_string_view<_CharT> __s)
- {
- span __to = _M_unused();
- while (__to.size() <= __s.size())
- {
- __s.copy(__to.data(), __to.size());
- _M_next += __to.size();
- __s.remove_prefix(__to.size());
- _M_overflow();
- __to = _M_unused();
- }
- if (__s.size())
- {
- __s.copy(__to.data(), __s.size());
- _M_next += __s.size();
- }
- }
- public:
- _Sink(const _Sink&) = delete;
- _Sink& operator=(const _Sink&) = delete;
- [[__gnu__::__always_inline__]]
- constexpr _Sink_iter<_CharT>
- out() noexcept
- { return _Sink_iter<_CharT>(*this); }
- };
- // A sink with an internal buffer. This is used to implement concrete sinks.
- template<typename _CharT>
- class _Buf_sink : public _Sink<_CharT>
- {
- protected:
- _CharT _M_buf[32 * sizeof(void*) / sizeof(_CharT)];
- [[__gnu__::__always_inline__]]
- constexpr
- _Buf_sink() noexcept
- : _Sink<_CharT>(_M_buf)
- { }
- };
- // A sink that fills a sequence (e.g. std::string, std::vector, std::deque).
- // Writes to a buffer then appends that to the sequence when it fills up.
- template<typename _Seq>
- class _Seq_sink final : public _Buf_sink<typename _Seq::value_type>
- {
- using _CharT = typename _Seq::value_type;
- _Seq _M_seq;
- // Transfer buffer contents to the sequence, so buffer can be refilled.
- void
- _M_overflow() override
- {
- auto __s = this->_M_used();
- if (__s.empty())
- return;
- if constexpr (__is_specialization_of<_Seq, basic_string>)
- _M_seq.append(__s.data(), __s.size());
- else
- _M_seq.insert(_M_seq.end(), __s.begin(), __s.end());
- this->_M_rewind();
- }
- public:
- // TODO: for SSO string, use SSO buffer as initial span, then switch
- // to _M_buf if it overflows? Or even do that for all unused capacity?
- [[__gnu__::__always_inline__]]
- _Seq_sink() noexcept(is_nothrow_default_constructible_v<_Seq>)
- { }
- _Seq_sink(_Seq&& __s) noexcept(is_nothrow_move_constructible_v<_Seq>)
- : _M_seq(std::move(__s))
- { }
- using _Sink<_CharT>::out;
- _Seq
- get() &&
- {
- if (this->_M_used().size() != 0)
- _Seq_sink::_M_overflow();
- return std::move(_M_seq);
- }
- };
- template<typename _CharT, typename _Alloc = allocator<_CharT>>
- using _Str_sink
- = _Seq_sink<basic_string<_CharT, char_traits<_CharT>, _Alloc>>;
- // template<typename _CharT, typename _Alloc = allocator<_CharT>>
- // using _Vec_sink = _Seq_sink<vector<_CharT, _Alloc>>;
- // A sink that writes to an output iterator.
- // Writes to a fixed-size buffer and then flushes to the output iterator
- // when the buffer fills up.
- template<typename _CharT, typename _OutIter>
- class _Iter_sink : public _Buf_sink<_CharT>
- {
- _OutIter _M_out;
- iter_difference_t<_OutIter> _M_max;
- protected:
- size_t _M_count = 0;
- void
- _M_overflow() override
- {
- auto __s = this->_M_used();
- if (_M_max < 0) // No maximum.
- _M_out = ranges::copy(__s, std::move(_M_out)).out;
- else if (_M_count < static_cast<size_t>(_M_max))
- {
- auto __max = _M_max - _M_count;
- span<_CharT> __first;
- if (__max < __s.size())
- __first = __s.first(static_cast<size_t>(__max));
- else
- __first = __s;
- _M_out = ranges::copy(__first, std::move(_M_out)).out;
- }
- this->_M_rewind();
- _M_count += __s.size();
- }
- public:
- [[__gnu__::__always_inline__]]
- explicit
- _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __max = -1)
- : _M_out(std::move(__out)), _M_max(__max)
- { }
- using _Sink<_CharT>::out;
- format_to_n_result<_OutIter>
- _M_finish() &&
- {
- if (this->_M_used().size() != 0)
- _Iter_sink::_M_overflow();
- iter_difference_t<_OutIter> __count(_M_count);
- return { std::move(_M_out), __count };
- }
- };
- // Partial specialization for contiguous iterators.
- // No buffer is used, characters are written straight to the iterator.
- // We do not know the size of the output range, so the span size just grows
- // as needed. The end of the span might be an invalid pointer outside the
- // valid range, but we never actually call _M_span.end(). This class does
- // not introduce any invalid pointer arithmetic or overflows that would not
- // have happened anyway.
- template<typename _CharT, contiguous_iterator _OutIter>
- requires same_as<iter_value_t<_OutIter>, _CharT>
- class _Iter_sink<_CharT, _OutIter> : public _Sink<_CharT>
- {
- _OutIter _M_first;
- iter_difference_t<_OutIter> _M_max = -1;
- protected:
- size_t _M_count = 0;
- private:
- _CharT _M_buf[64]; // Write here after outputting _M_max characters.
- protected:
- void
- _M_overflow() override
- {
- if (this->_M_unused().size() != 0)
- return; // No need to switch to internal buffer yet.
- auto __s = this->_M_used();
- if (_M_max >= 0)
- {
- _M_count += __s.size();
- // Span was already sized for the maximum character count,
- // if it overflows then any further output must go to the
- // internal buffer, to be discarded.
- this->_M_reset(this->_M_buf);
- }
- else
- {
- // No maximum character count. Just extend the span to allow
- // writing more characters to it.
- this->_M_reset({__s.data(), __s.size() + 1024}, __s.size());
- }
- }
- private:
- static span<_CharT>
- _S_make_span(_CharT* __ptr, iter_difference_t<_OutIter> __n,
- span<_CharT> __buf) noexcept
- {
- if (__n == 0)
- return __buf; // Only write to the internal buffer.
- if (__n > 0)
- {
- if constexpr (!is_integral_v<iter_difference_t<_OutIter>>
- || sizeof(__n) > sizeof(size_t))
- {
- // __int128 or __detail::__max_diff_type
- auto __m = iter_difference_t<_OutIter>((size_t)-1);
- if (__n > __m)
- __n = __m;
- }
- return {__ptr, (size_t)__n};
- }
- #if __has_builtin(__builtin_dynamic_object_size)
- if (size_t __bytes = __builtin_dynamic_object_size(__ptr, 2))
- return {__ptr, __bytes / sizeof(_CharT)};
- #endif
- // Avoid forming a pointer to a different memory page.
- const auto __off = reinterpret_cast<__UINTPTR_TYPE__>(__ptr) % 1024;
- __n = (1024 - __off) / sizeof(_CharT);
- if (__n > 0) [[likely]]
- return {__ptr, static_cast<size_t>(__n)};
- else // Misaligned/packed buffer of wchar_t?
- return {__ptr, 1};
- }
- public:
- explicit
- _Iter_sink(_OutIter __out, iter_difference_t<_OutIter> __n = -1) noexcept
- : _Sink<_CharT>(_S_make_span(std::to_address(__out), __n, _M_buf)),
- _M_first(__out), _M_max(__n)
- { }
- format_to_n_result<_OutIter>
- _M_finish() &&
- {
- auto __s = this->_M_used();
- if (__s.data() == _M_buf)
- {
- // Switched to internal buffer, so must have written _M_max.
- iter_difference_t<_OutIter> __count(_M_count + __s.size());
- return { _M_first + _M_max, __count };
- }
- else // Not using internal buffer yet
- {
- iter_difference_t<_OutIter> __count(__s.size());
- return { _M_first + __count, __count };
- }
- }
- };
- enum _Arg_t : unsigned char {
- _Arg_none, _Arg_bool, _Arg_c, _Arg_i, _Arg_u, _Arg_ll, _Arg_ull,
- _Arg_flt, _Arg_dbl, _Arg_ldbl, _Arg_str, _Arg_sv, _Arg_ptr, _Arg_handle,
- _Arg_i128, _Arg_u128,
- _Arg_bf16, _Arg_f16, _Arg_f32, _Arg_f64, // These are unused.
- #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- _Arg_next_value_,
- _Arg_f128 = _Arg_ldbl,
- _Arg_ibm128 = _Arg_next_value_,
- #else
- _Arg_f128,
- #endif
- _Arg_max_
- };
- template<typename _Context>
- struct _Arg_value
- {
- using _CharT = typename _Context::char_type;
- struct _HandleBase
- {
- const void* _M_ptr;
- void (*_M_func)();
- };
- union
- {
- monostate _M_none;
- bool _M_bool;
- _CharT _M_c;
- int _M_i;
- unsigned _M_u;
- long long _M_ll;
- unsigned long long _M_ull;
- float _M_flt;
- double _M_dbl;
- #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT // No long double if it's ambiguous.
- long double _M_ldbl;
- #endif
- const _CharT* _M_str;
- basic_string_view<_CharT> _M_sv;
- const void* _M_ptr;
- _HandleBase _M_handle;
- #ifdef __SIZEOF_INT128__
- __int128 _M_i128;
- unsigned __int128 _M_u128;
- #endif
- // TODO _Float16 etc.
- #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- __ieee128 _M_f128;
- __ibm128 _M_ibm128;
- #elif _GLIBCXX_FORMAT_F128 == 2
- __float128_t _M_f128;
- #endif
- };
- [[__gnu__::__always_inline__]]
- _Arg_value() : _M_none() { }
- #if 0
- template<typename _Tp>
- _Arg_value(in_place_type_t<_Tp>, _Tp __val)
- { _S_get<_Tp>() = __val; }
- #endif
- template<typename _Tp, typename _Self>
- [[__gnu__::__always_inline__]]
- static auto&
- _S_get(_Self& __u) noexcept
- {
- if constexpr (is_same_v<_Tp, bool>)
- return __u._M_bool;
- else if constexpr (is_same_v<_Tp, _CharT>)
- return __u._M_c;
- else if constexpr (is_same_v<_Tp, int>)
- return __u._M_i;
- else if constexpr (is_same_v<_Tp, unsigned>)
- return __u._M_u;
- else if constexpr (is_same_v<_Tp, long long>)
- return __u._M_ll;
- else if constexpr (is_same_v<_Tp, unsigned long long>)
- return __u._M_ull;
- else if constexpr (is_same_v<_Tp, float>)
- return __u._M_flt;
- else if constexpr (is_same_v<_Tp, double>)
- return __u._M_dbl;
- #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- else if constexpr (is_same_v<_Tp, long double>)
- return __u._M_ldbl;
- #else
- else if constexpr (is_same_v<_Tp, __ieee128>)
- return __u._M_f128;
- else if constexpr (is_same_v<_Tp, __ibm128>)
- return __u._M_ibm128;
- #endif
- else if constexpr (is_same_v<_Tp, const _CharT*>)
- return __u._M_str;
- else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
- return __u._M_sv;
- else if constexpr (is_same_v<_Tp, const void*>)
- return __u._M_ptr;
- #ifdef __SIZEOF_INT128__
- else if constexpr (is_same_v<_Tp, __int128>)
- return __u._M_i128;
- else if constexpr (is_same_v<_Tp, unsigned __int128>)
- return __u._M_u128;
- #endif
- #if _GLIBCXX_FORMAT_F128 == 2
- else if constexpr (is_same_v<_Tp, __float128_t>)
- return __u._M_f128;
- #endif
- else if constexpr (derived_from<_Tp, _HandleBase>)
- return static_cast<_Tp&>(__u._M_handle);
- // Otherwise, ill-formed.
- }
- template<typename _Tp>
- [[__gnu__::__always_inline__]]
- auto&
- _M_get() noexcept
- { return _S_get<_Tp>(*this); }
- template<typename _Tp>
- [[__gnu__::__always_inline__]]
- const auto&
- _M_get() const noexcept
- { return _S_get<_Tp>(*this); }
- template<typename _Tp>
- [[__gnu__::__always_inline__]]
- void
- _M_set(_Tp __v) noexcept
- {
- if constexpr (derived_from<_Tp, _HandleBase>)
- std::construct_at(&_M_handle, __v);
- else
- _S_get<_Tp>(*this) = __v;
- }
- };
- // [format.arg.store], class template format-arg-store
- template<typename _Context, typename... _Args>
- class _Arg_store;
- } // namespace __format
- /// @endcond
- template<typename _Context>
- class basic_format_arg
- {
- using _CharT = typename _Context::char_type;
- template<typename _Tp>
- static constexpr bool __formattable
- = __format::__formattable_with<_Tp, _Context>;
- public:
- class handle : public __format::_Arg_value<_Context>::_HandleBase
- {
- using _Base = typename __format::_Arg_value<_Context>::_HandleBase;
- // Format as const if possible, to reduce instantiations.
- template<typename _Tp>
- using __maybe_const_t
- = __conditional_t<__formattable<const _Tp>, const _Tp, _Tp>;
- template<typename _Tq>
- static void
- _S_format(basic_format_parse_context<_CharT>& __parse_ctx,
- _Context& __format_ctx, const void* __ptr)
- {
- using _Td = remove_const_t<_Tq>;
- typename _Context::template formatter_type<_Td> __f;
- __parse_ctx.advance_to(__f.parse(__parse_ctx));
- _Tq& __val = *const_cast<_Tq*>(static_cast<const _Td*>(__ptr));
- __format_ctx.advance_to(__f.format(__val, __format_ctx));
- }
- template<typename _Tp>
- explicit
- handle(_Tp& __val) noexcept
- {
- this->_M_ptr = __builtin_addressof(__val);
- auto __func = _S_format<__maybe_const_t<_Tp>>;
- this->_M_func = reinterpret_cast<void(*)()>(__func);
- }
- friend class basic_format_arg<_Context>;
- public:
- handle(const handle&) = default;
- handle& operator=(const handle&) = default;
- [[__gnu__::__always_inline__]]
- void
- format(basic_format_parse_context<_CharT>& __pc, _Context& __fc) const
- {
- using _Func = void(*)(basic_format_parse_context<_CharT>&,
- _Context&, const void*);
- auto __f = reinterpret_cast<_Func>(this->_M_func);
- __f(__pc, __fc, this->_M_ptr);
- }
- };
- [[__gnu__::__always_inline__]]
- basic_format_arg() noexcept : _M_type(__format::_Arg_none) { }
- [[nodiscard,__gnu__::__always_inline__]]
- explicit operator bool() const noexcept
- { return _M_type != __format::_Arg_none; }
- private:
- template<typename _Ctx>
- friend class basic_format_args;
- template<typename _Ctx, typename... _Args>
- friend class __format::_Arg_store;
- static_assert(is_trivially_copyable_v<__format::_Arg_value<_Context>>);
- __format::_Arg_value<_Context> _M_val;
- __format::_Arg_t _M_type;
- // Transform incoming argument type to the type stored in _Arg_value.
- // e.g. short -> int, std::string -> std::string_view,
- // char[3] -> const char*.
- template<typename _Tp>
- static consteval auto
- _S_to_arg_type()
- {
- using _Td = remove_const_t<_Tp>;
- if constexpr (is_same_v<_Td, bool>)
- return type_identity<bool>();
- else if constexpr (is_same_v<_Td, _CharT>)
- return type_identity<_CharT>();
- else if constexpr (is_same_v<_Td, char> && is_same_v<_CharT, wchar_t>)
- return type_identity<_CharT>();
- #ifdef __SIZEOF_INT128__ // Check before signed/unsigned integer
- else if constexpr (is_same_v<_Td, __int128>)
- return type_identity<__int128>();
- else if constexpr (is_same_v<_Td, unsigned __int128>)
- return type_identity<unsigned __int128>();
- #endif
- else if constexpr (__is_signed_integer<_Td>::value)
- {
- if constexpr (sizeof(_Td) <= sizeof(int))
- return type_identity<int>();
- else if constexpr (sizeof(_Td) <= sizeof(long long))
- return type_identity<long long>();
- }
- else if constexpr (__is_unsigned_integer<_Td>::value)
- {
- if constexpr (sizeof(_Td) <= sizeof(unsigned))
- return type_identity<unsigned>();
- else if constexpr (sizeof(_Td) <= sizeof(unsigned long long))
- return type_identity<unsigned long long>();
- }
- else if constexpr (is_same_v<_Td, float>)
- return type_identity<float>();
- else if constexpr (is_same_v<_Td, double>)
- return type_identity<double>();
- #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- else if constexpr (is_same_v<_Td, long double>)
- return type_identity<long double>();
- #else
- else if constexpr (is_same_v<_Td, __ibm128>)
- return type_identity<__ibm128>();
- else if constexpr (is_same_v<_Td, __ieee128>)
- return type_identity<__ieee128>();
- #endif
- // TODO bfloat16 and float16
- #ifdef __FLT32_DIG__
- else if constexpr (is_same_v<_Td, _Float32>)
- # ifdef _GLIBCXX_FLOAT_IS_IEEE_BINARY32
- return type_identity<float>();
- # else
- return type_identity<_Float32>();
- # endif
- #endif
- #ifdef __FLT64_DIG__
- else if constexpr (is_same_v<_Td, _Float64>)
- # ifdef _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
- return type_identity<double>();
- # else
- return type_identity<_Float64>();
- # endif
- #endif
- #if _GLIBCXX_FORMAT_F128
- # if __FLT128_DIG__
- else if constexpr (is_same_v<_Td, _Float128>)
- return type_identity<__format::__float128_t>();
- # endif
- # if __SIZEOF_FLOAT128__
- else if constexpr (is_same_v<_Td, __float128>)
- return type_identity<__format::__float128_t>();
- # endif
- #endif
- else if constexpr (__is_specialization_of<_Td, basic_string_view>
- || __is_specialization_of<_Td, basic_string>)
- {
- if constexpr (is_same_v<typename _Td::value_type, _CharT>)
- return type_identity<basic_string_view<_CharT>>();
- else
- return type_identity<handle>();
- }
- else if constexpr (is_same_v<decay_t<_Td>, const _CharT*>)
- return type_identity<const _CharT*>();
- else if constexpr (is_same_v<decay_t<_Td>, _CharT*>)
- return type_identity<const _CharT*>();
- else if constexpr (is_void_v<remove_pointer_t<_Td>>)
- return type_identity<const void*>();
- else if constexpr (is_same_v<_Td, nullptr_t>)
- return type_identity<const void*>();
- else
- return type_identity<handle>();
- }
- // Transform a formattable type to the appropriate storage type.
- template<typename _Tp>
- using _Normalize = typename decltype(_S_to_arg_type<_Tp>())::type;
- // Get the _Arg_t value corresponding to a normalized type.
- template<typename _Tp>
- static consteval __format::_Arg_t
- _S_to_enum()
- {
- using namespace __format;
- if constexpr (is_same_v<_Tp, bool>)
- return _Arg_bool;
- else if constexpr (is_same_v<_Tp, _CharT>)
- return _Arg_c;
- else if constexpr (is_same_v<_Tp, int>)
- return _Arg_i;
- else if constexpr (is_same_v<_Tp, unsigned>)
- return _Arg_u;
- else if constexpr (is_same_v<_Tp, long long>)
- return _Arg_ll;
- else if constexpr (is_same_v<_Tp, unsigned long long>)
- return _Arg_ull;
- else if constexpr (is_same_v<_Tp, float>)
- return _Arg_flt;
- else if constexpr (is_same_v<_Tp, double>)
- return _Arg_dbl;
- #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- else if constexpr (is_same_v<_Tp, long double>)
- return _Arg_ldbl;
- #else
- // Don't use _Arg_ldbl for this target, it's ambiguous.
- else if constexpr (is_same_v<_Tp, __ibm128>)
- return _Arg_ibm128;
- else if constexpr (is_same_v<_Tp, __ieee128>)
- return _Arg_f128;
- #endif
- else if constexpr (is_same_v<_Tp, const _CharT*>)
- return _Arg_str;
- else if constexpr (is_same_v<_Tp, basic_string_view<_CharT>>)
- return _Arg_sv;
- else if constexpr (is_same_v<_Tp, const void*>)
- return _Arg_ptr;
- #ifdef __SIZEOF_INT128__
- else if constexpr (is_same_v<_Tp, __int128>)
- return _Arg_i128;
- else if constexpr (is_same_v<_Tp, unsigned __int128>)
- return _Arg_u128;
- #endif
- // N.B. some of these types will never actually be used here,
- // because they get normalized to a standard floating-point type.
- #if defined __FLT32_DIG__ && ! _GLIBCXX_FLOAT_IS_IEEE_BINARY32
- else if constexpr (is_same_v<_Tp, _Float32>)
- return _Arg_f32;
- #endif
- #if defined __FLT64_DIG__ && ! _GLIBCXX_DOUBLE_IS_IEEE_BINARY64
- else if constexpr (is_same_v<_Tp, _Float64>)
- return _Arg_f64;
- #endif
- #if _GLIBCXX_FORMAT_F128 == 2
- else if constexpr (is_same_v<_Tp, __format::__float128_t>)
- return _Arg_f128;
- #endif
- else if constexpr (is_same_v<_Tp, handle>)
- return _Arg_handle;
- }
- template<typename _Tp>
- void
- _M_set(_Tp __v) noexcept
- {
- _M_type = _S_to_enum<_Tp>();
- _M_val._M_set(__v);
- }
- template<typename _Tp>
- requires __format::__formattable_with<_Tp, _Context>
- explicit
- basic_format_arg(_Tp& __v) noexcept
- {
- using _Td = _Normalize<_Tp>;
- if constexpr (is_same_v<_Td, basic_string_view<_CharT>>)
- _M_set(_Td{__v.data(), __v.size()});
- else if constexpr (is_same_v<remove_const_t<_Tp>, char>
- && is_same_v<_CharT, wchar_t>)
- _M_set(static_cast<_Td>(static_cast<unsigned char>(__v)));
- else
- _M_set(static_cast<_Td>(__v));
- }
- template<typename _Ctx, typename... _Argz>
- friend auto
- make_format_args(_Argz&...) noexcept;
- template<typename _Visitor, typename _Ctx>
- friend decltype(auto)
- visit_format_arg(_Visitor&& __vis, basic_format_arg<_Ctx>);
- template<typename _Visitor>
- decltype(auto)
- _M_visit(_Visitor&& __vis, __format::_Arg_t __type)
- {
- using namespace __format;
- switch (__type)
- {
- case _Arg_none:
- return std::forward<_Visitor>(__vis)(_M_val._M_none);
- case _Arg_bool:
- return std::forward<_Visitor>(__vis)(_M_val._M_bool);
- case _Arg_c:
- return std::forward<_Visitor>(__vis)(_M_val._M_c);
- case _Arg_i:
- return std::forward<_Visitor>(__vis)(_M_val._M_i);
- case _Arg_u:
- return std::forward<_Visitor>(__vis)(_M_val._M_u);
- case _Arg_ll:
- return std::forward<_Visitor>(__vis)(_M_val._M_ll);
- case _Arg_ull:
- return std::forward<_Visitor>(__vis)(_M_val._M_ull);
- #if __cpp_lib_to_chars // FIXME: need to be able to format these types!
- case _Arg_flt:
- return std::forward<_Visitor>(__vis)(_M_val._M_flt);
- case _Arg_dbl:
- return std::forward<_Visitor>(__vis)(_M_val._M_dbl);
- #ifndef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
- case _Arg_ldbl:
- return std::forward<_Visitor>(__vis)(_M_val._M_ldbl);
- #else
- case _Arg_f128:
- return std::forward<_Visitor>(__vis)(_M_val._M_f128);
- case _Arg_ibm128:
- return std::forward<_Visitor>(__vis)(_M_val._M_ibm128);
- #endif
- #endif
- case _Arg_str:
- return std::forward<_Visitor>(__vis)(_M_val._M_str);
- case _Arg_sv:
- return std::forward<_Visitor>(__vis)(_M_val._M_sv);
- case _Arg_ptr:
- return std::forward<_Visitor>(__vis)(_M_val._M_ptr);
- case _Arg_handle:
- {
- auto& __h = static_cast<handle&>(_M_val._M_handle);
- return std::forward<_Visitor>(__vis)(__h);
- }
- #ifdef __SIZEOF_INT128__
- case _Arg_i128:
- return std::forward<_Visitor>(__vis)(_M_val._M_i128);
- case _Arg_u128:
- return std::forward<_Visitor>(__vis)(_M_val._M_u128);
- #endif
- #if _GLIBCXX_FORMAT_F128 == 2
- case _Arg_f128:
- return std::forward<_Visitor>(__vis)(_M_val._M_f128);
- #endif
- default:
- // _Arg_f16 etc.
- __builtin_unreachable();
- }
- }
- };
- template<typename _Visitor, typename _Context>
- inline decltype(auto)
- visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg)
- {
- return __arg._M_visit(std::forward<_Visitor>(__vis), __arg._M_type);
- }
- /// @cond undocumented
- namespace __format
- {
- struct _WidthPrecVisitor
- {
- template<typename _Tp>
- size_t
- operator()(_Tp& __arg) const
- {
- if constexpr (is_same_v<_Tp, monostate>)
- __format::__invalid_arg_id_in_format_string();
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3720. Restrict the valid types of arg-id for width and precision
- // 3721. Allow an arg-id with a value of zero for width
- else if constexpr (sizeof(_Tp) <= sizeof(long long))
- {
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3720. Restrict the valid types of arg-id for width and precision
- if constexpr (__is_unsigned_integer<_Tp>::value)
- return __arg;
- else if constexpr (__is_signed_integer<_Tp>::value)
- if (__arg >= 0)
- return __arg;
- }
- __throw_format_error("format error: argument used for width or "
- "precision must be a non-negative integer");
- }
- };
- template<typename _Context>
- inline size_t
- __int_from_arg(const basic_format_arg<_Context>& __arg)
- { return std::visit_format_arg(_WidthPrecVisitor(), __arg); }
- // Pack _Arg_t enum values into a single 60-bit integer.
- template<int _Bits, size_t _Nm>
- constexpr auto
- __pack_arg_types(const array<_Arg_t, _Nm>& __types)
- {
- __UINT64_TYPE__ __packed_types = 0;
- for (auto __i = __types.rbegin(); __i != __types.rend(); ++__i)
- __packed_types = (__packed_types << _Bits) | *__i;
- return __packed_types;
- }
- } // namespace __format
- /// @endcond
- template<typename _Context>
- class basic_format_args
- {
- static constexpr int _S_packed_type_bits = 5; // _Arg_t values [0,20]
- static constexpr int _S_packed_type_mask = 0b11111;
- static constexpr int _S_max_packed_args = 12;
- static_assert( __format::_Arg_max_ <= (1 << _S_packed_type_bits) );
- template<typename... _Args>
- using _Store = __format::_Arg_store<_Context, _Args...>;
- template<typename _Ctx, typename... _Args>
- friend class __format::_Arg_store;
- using uint64_t = __UINT64_TYPE__;
- using _Format_arg = basic_format_arg<_Context>;
- using _Format_arg_val = __format::_Arg_value<_Context>;
- // If args are packed then the number of args is in _M_packed_size and
- // the packed types are in _M_unpacked_size, accessed via _M_type(i).
- // If args are not packed then the number of args is in _M_unpacked_size
- // and _M_packed_size is zero.
- uint64_t _M_packed_size : 4;
- uint64_t _M_unpacked_size : 60;
- union {
- const _Format_arg_val* _M_values; // Active when _M_packed_size != 0
- const _Format_arg* _M_args; // Active when _M_packed_size == 0
- };
- size_t
- _M_size() const noexcept
- { return _M_packed_size ? _M_packed_size : _M_unpacked_size; }
- typename __format::_Arg_t
- _M_type(size_t __i) const noexcept
- {
- uint64_t __t = _M_unpacked_size >> (__i * _S_packed_type_bits);
- return static_cast<__format::_Arg_t>(__t & _S_packed_type_mask);
- }
- template<typename _Ctx, typename... _Args>
- friend auto
- make_format_args(_Args&...) noexcept;
- // An array of _Arg_t enums corresponding to _Args...
- template<typename... _Args>
- static consteval array<__format::_Arg_t, sizeof...(_Args)>
- _S_types_to_pack()
- { return {_Format_arg::template _S_to_enum<_Args>()...}; }
- public:
- basic_format_args() noexcept = default;
- template<typename... _Args>
- basic_format_args(const _Store<_Args...>& __store) noexcept;
- [[nodiscard,__gnu__::__always_inline__]]
- basic_format_arg<_Context>
- get(size_t __i) const noexcept
- {
- basic_format_arg<_Context> __arg;
- if (__i < _M_packed_size)
- {
- __arg._M_type = _M_type(__i);
- __arg._M_val = _M_values[__i];
- }
- else if (_M_packed_size == 0 && __i < _M_unpacked_size)
- __arg = _M_args[__i];
- return __arg;
- }
- };
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 3810. CTAD for std::basic_format_args
- template<typename _Context, typename... _Args>
- basic_format_args(__format::_Arg_store<_Context, _Args...>)
- -> basic_format_args<_Context>;
- template<typename _Context, typename... _Args>
- auto
- make_format_args(_Args&... __fmt_args) noexcept;
- // An array of type-erased formatting arguments.
- template<typename _Context, typename... _Args>
- class __format::_Arg_store
- {
- friend std::basic_format_args<_Context>;
- template<typename _Ctx, typename... _Argz>
- friend auto std::
- #if _GLIBCXX_INLINE_VERSION
- __8:: // Needed for PR c++/59256
- #endif
- make_format_args(_Argz&...) noexcept;
- // For a sufficiently small number of arguments we only store values.
- // basic_format_args can get the types from the _Args pack.
- static constexpr bool _S_values_only
- = sizeof...(_Args) <= basic_format_args<_Context>::_S_max_packed_args;
- using _Element_t
- = __conditional_t<_S_values_only,
- __format::_Arg_value<_Context>,
- basic_format_arg<_Context>>;
- _Element_t _M_args[sizeof...(_Args)];
- template<typename _Tp>
- static _Element_t
- _S_make_elt(_Tp& __v)
- {
- basic_format_arg<_Context> __arg(__v);
- if constexpr (_S_values_only)
- return __arg._M_val;
- else
- return __arg;
- }
- template<typename... _Tp>
- requires (sizeof...(_Tp) == sizeof...(_Args))
- [[__gnu__::__always_inline__]]
- _Arg_store(_Tp&... __a) noexcept
- : _M_args{_S_make_elt(__a)...}
- { }
- };
- template<typename _Context>
- class __format::_Arg_store<_Context>
- { };
- template<typename _Context>
- template<typename... _Args>
- inline
- basic_format_args<_Context>::
- basic_format_args(const _Store<_Args...>& __store) noexcept
- {
- if constexpr (sizeof...(_Args) == 0)
- {
- _M_packed_size = 0;
- _M_unpacked_size = 0;
- _M_args = nullptr;
- }
- else if constexpr (sizeof...(_Args) <= _S_max_packed_args)
- {
- // The number of packed arguments:
- _M_packed_size = sizeof...(_Args);
- // The packed type enums:
- _M_unpacked_size
- = __format::__pack_arg_types<_S_packed_type_bits>(_S_types_to_pack<_Args...>());
- // The _Arg_value objects.
- _M_values = __store._M_args;
- }
- else
- {
- // No packed arguments:
- _M_packed_size = 0;
- // The number of unpacked arguments:
- _M_unpacked_size = sizeof...(_Args);
- // The basic_format_arg objects:
- _M_args = __store._M_args;
- }
- }
- /// Capture formatting arguments for use by `std::vformat`.
- template<typename _Context = format_context, typename... _Args>
- [[nodiscard,__gnu__::__always_inline__]]
- inline auto
- make_format_args(_Args&... __fmt_args) noexcept
- {
- using _Fmt_arg = basic_format_arg<_Context>;
- using _Store = __format::_Arg_store<_Context, typename _Fmt_arg::template
- _Normalize<_Args>...>;
- return _Store(__fmt_args...);
- }
- /// Capture formatting arguments for use by `std::vformat` (for wide output).
- template<typename... _Args>
- [[nodiscard,__gnu__::__always_inline__]]
- inline auto
- make_wformat_args(_Args&... __args) noexcept
- { return std::make_format_args<wformat_context>(__args...); }
- /// @cond undocumented
- namespace __format
- {
- template<typename _Out, typename _CharT, typename _Context>
- _Out
- __do_vformat_to(_Out, basic_string_view<_CharT>,
- const basic_format_args<_Context>&,
- const locale* = nullptr);
- } // namespace __format
- /// @endcond
- /** Context for std::format and similar functions.
- *
- * A formatting context contains an output iterator and locale to use
- * for the formatting operations. Most programs will never need to use
- * this class template explicitly. For typical uses of `std::format` the
- * library will use the specializations `std::format_context` (for `char`)
- * and `std::wformat_context` (for `wchar_t`).
- */
- template<typename _Out, typename _CharT>
- class basic_format_context
- {
- static_assert( output_iterator<_Out, const _CharT&> );
- basic_format_args<basic_format_context> _M_args;
- _Out _M_out;
- __format::_Optional_locale _M_loc;
- basic_format_context(basic_format_args<basic_format_context> __args,
- _Out __out)
- : _M_args(__args), _M_out(std::move(__out))
- { }
- basic_format_context(basic_format_args<basic_format_context> __args,
- _Out __out, const std::locale& __loc)
- : _M_args(__args), _M_out(std::move(__out)), _M_loc(__loc)
- { }
- template<typename _Out2, typename _CharT2, typename _Context2>
- friend _Out2
- __format::__do_vformat_to(_Out2, basic_string_view<_CharT2>,
- const basic_format_args<_Context2>&,
- const locale*);
- public:
- basic_format_context() = default;
- ~basic_format_context() = default;
- using iterator = _Out;
- using char_type = _CharT;
- template<typename _Tp>
- using formatter_type = formatter<_Tp, _CharT>;
- [[nodiscard]]
- basic_format_arg<basic_format_context>
- arg(size_t __id) const noexcept
- { return _M_args.get(__id); }
- [[nodiscard]]
- std::locale locale() { return _M_loc.value(); }
- [[nodiscard]]
- iterator out() { return std::move(_M_out); }
- void advance_to(iterator __it) { _M_out = std::move(__it); }
- };
- /// @cond undocumented
- namespace __format
- {
- // Abstract base class defining an interface for scanning format strings.
- // Scan the characters in a format string, dividing it up into strings of
- // ordinary characters, escape sequences, and replacement fields.
- // Call virtual functions for derived classes to parse format-specifiers
- // or write formatted output.
- template<typename _CharT>
- struct _Scanner
- {
- using iterator = typename basic_format_parse_context<_CharT>::iterator;
- basic_format_parse_context<_CharT> _M_pc;
- constexpr explicit
- _Scanner(basic_string_view<_CharT> __str, size_t __nargs = -1)
- : _M_pc(__str, __nargs)
- { }
- constexpr iterator begin() const noexcept { return _M_pc.begin(); }
- constexpr iterator end() const noexcept { return _M_pc.end(); }
- constexpr void
- _M_scan()
- {
- basic_string_view<_CharT> __fmt = _M_fmt_str();
- if (__fmt.size() == 2 && __fmt[0] == '{' && __fmt[1] == '}')
- {
- _M_pc.advance_to(begin() + 1);
- _M_format_arg(_M_pc.next_arg_id());
- return;
- }
- size_t __lbr = __fmt.find('{');
- size_t __rbr = __fmt.find('}');
- while (__fmt.size())
- {
- auto __cmp = __lbr <=> __rbr;
- if (__cmp == 0)
- {
- _M_on_chars(end());
- _M_pc.advance_to(end());
- return;
- }
- else if (__cmp < 0)
- {
- if (__lbr + 1 == __fmt.size()
- || (__rbr == __fmt.npos && __fmt[__lbr + 1] != '{'))
- __format::__unmatched_left_brace_in_format_string();
- const bool __is_escape = __fmt[__lbr + 1] == '{';
- iterator __last = begin() + __lbr + int(__is_escape);
- _M_on_chars(__last);
- _M_pc.advance_to(__last + 1);
- __fmt = _M_fmt_str();
- if (__is_escape)
- {
- if (__rbr != __fmt.npos)
- __rbr -= __lbr + 2;
- __lbr = __fmt.find('{');
- }
- else
- {
- _M_on_replacement_field();
- __fmt = _M_fmt_str();
- __lbr = __fmt.find('{');
- __rbr = __fmt.find('}');
- }
- }
- else
- {
- if (++__rbr == __fmt.size() || __fmt[__rbr] != '}')
- __format::__unmatched_right_brace_in_format_string();
- iterator __last = begin() + __rbr;
- _M_on_chars(__last);
- _M_pc.advance_to(__last + 1);
- __fmt = _M_fmt_str();
- if (__lbr != __fmt.npos)
- __lbr -= __rbr + 1;
- __rbr = __fmt.find('}');
- }
- }
- }
- constexpr basic_string_view<_CharT>
- _M_fmt_str() const noexcept
- { return {begin(), end()}; }
- constexpr virtual void _M_on_chars(iterator) { }
- constexpr void _M_on_replacement_field()
- {
- auto __next = begin();
- size_t __id;
- if (*__next == '}')
- __id = _M_pc.next_arg_id();
- else if (*__next == ':')
- {
- __id = _M_pc.next_arg_id();
- _M_pc.advance_to(++__next);
- }
- else
- {
- auto [__i, __ptr] = __format::__parse_arg_id(begin(), end());
- if (!__ptr || !(*__ptr == '}' || *__ptr == ':'))
- __format::__invalid_arg_id_in_format_string();
- _M_pc.check_arg_id(__id = __i);
- if (*__ptr == ':')
- {
- _M_pc.advance_to(++__ptr);
- }
- else
- _M_pc.advance_to(__ptr);
- }
- _M_format_arg(__id);
- if (begin() == end() || *begin() != '}')
- __format::__unmatched_left_brace_in_format_string();
- _M_pc.advance_to(begin() + 1); // Move past '}'
- }
- constexpr virtual void _M_format_arg(size_t __id) = 0;
- };
- // Process a format string and format the arguments in the context.
- template<typename _Out, typename _CharT>
- class _Formatting_scanner : public _Scanner<_CharT>
- {
- public:
- _Formatting_scanner(basic_format_context<_Out, _CharT>& __fc,
- basic_string_view<_CharT> __str)
- : _Scanner<_CharT>(__str), _M_fc(__fc)
- { }
- private:
- basic_format_context<_Out, _CharT>& _M_fc;
- using iterator = typename _Scanner<_CharT>::iterator;
- constexpr void
- _M_on_chars(iterator __last) override
- {
- basic_string_view<_CharT> __str(this->begin(), __last);
- _M_fc.advance_to(__format::__write(_M_fc.out(), __str));
- }
- constexpr void
- _M_format_arg(size_t __id) override
- {
- using _Context = basic_format_context<_Out, _CharT>;
- using handle = typename basic_format_arg<_Context>::handle;
- std::visit_format_arg([this](auto& __arg) {
- using _Type = remove_reference_t<decltype(__arg)>;
- using _Formatter = typename _Context::template formatter_type<_Type>;
- if constexpr (is_same_v<_Type, monostate>)
- __format::__invalid_arg_id_in_format_string();
- else if constexpr (is_same_v<_Type, handle>)
- __arg.format(this->_M_pc, this->_M_fc);
- else if constexpr (is_default_constructible_v<_Formatter>)
- {
- _Formatter __f;
- this->_M_pc.advance_to(__f.parse(this->_M_pc));
- this->_M_fc.advance_to(__f.format(__arg, this->_M_fc));
- }
- else
- static_assert(__format::__formattable_with<_Type, _Context>);
- }, _M_fc.arg(__id));
- }
- };
- // Validate a format string for Args.
- template<typename _CharT, typename... _Args>
- class _Checking_scanner : public _Scanner<_CharT>
- {
- static_assert(
- (is_default_constructible_v<formatter<_Args, _CharT>> && ...),
- "std::formatter must be specialized for each type being formatted");
- public:
- constexpr
- _Checking_scanner(basic_string_view<_CharT> __str)
- : _Scanner<_CharT>(__str, sizeof...(_Args))
- { }
- private:
- constexpr void
- _M_format_arg(size_t __id) override
- {
- if constexpr (sizeof...(_Args) != 0)
- {
- if (__id < sizeof...(_Args))
- {
- _M_parse_format_spec<_Args...>(__id);
- return;
- }
- }
- __builtin_unreachable();
- }
- template<typename _Tp, typename... _OtherArgs>
- constexpr void
- _M_parse_format_spec(size_t __id)
- {
- if (__id == 0)
- {
- formatter<_Tp, _CharT> __f;
- this->_M_pc.advance_to(__f.parse(this->_M_pc));
- }
- else if constexpr (sizeof...(_OtherArgs) != 0)
- _M_parse_format_spec<_OtherArgs...>(__id - 1);
- else
- __builtin_unreachable();
- }
- };
- template<typename _Out, typename _CharT, typename _Context>
- inline _Out
- __do_vformat_to(_Out __out, basic_string_view<_CharT> __fmt,
- const basic_format_args<_Context>& __args,
- const locale* __loc)
- {
- _Iter_sink<_CharT, _Out> __sink(std::move(__out));
- _Sink_iter<_CharT> __sink_out;
- if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
- __sink_out = __out; // Already a sink iterator, safe to use post-move.
- else
- __sink_out = __sink.out();
- auto __ctx = __loc == nullptr
- ? _Context(__args, __sink_out)
- : _Context(__args, __sink_out, *__loc);
- _Formatting_scanner<_Sink_iter<_CharT>, _CharT> __scanner(__ctx, __fmt);
- __scanner._M_scan();
- if constexpr (is_same_v<_Out, _Sink_iter<_CharT>>)
- return __ctx.out();
- else
- return std::move(__sink)._M_finish().out;
- }
- } // namespace __format
- /// @endcond
- template<typename _CharT, typename... _Args>
- template<typename _Tp>
- requires convertible_to<const _Tp&, basic_string_view<_CharT>>
- consteval
- basic_format_string<_CharT, _Args...>::
- basic_format_string(const _Tp& __s)
- : _M_str(__s)
- {
- __format::_Checking_scanner<_CharT, remove_cvref_t<_Args>...>
- __scanner(_M_str);
- __scanner._M_scan();
- }
- // [format.functions], formatting functions
- template<typename _Out> requires output_iterator<_Out, const char&>
- [[__gnu__::__always_inline__]]
- inline _Out
- vformat_to(_Out __out, string_view __fmt, format_args __args)
- { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
- template<typename _Out> requires output_iterator<_Out, const wchar_t&>
- [[__gnu__::__always_inline__]]
- inline _Out
- vformat_to(_Out __out, wstring_view __fmt, wformat_args __args)
- { return __format::__do_vformat_to(std::move(__out), __fmt, __args); }
- template<typename _Out> requires output_iterator<_Out, const char&>
- [[__gnu__::__always_inline__]]
- inline _Out
- vformat_to(_Out __out, const locale& __loc, string_view __fmt,
- format_args __args)
- { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); }
- template<typename _Out> requires output_iterator<_Out, const wchar_t&>
- [[__gnu__::__always_inline__]]
- inline _Out
- vformat_to(_Out __out, const locale& __loc, wstring_view __fmt,
- wformat_args __args)
- { return __format::__do_vformat_to(std::move(__out), __fmt, __args, &__loc); }
- [[nodiscard]]
- inline string
- vformat(string_view __fmt, format_args __args)
- {
- __format::_Str_sink<char> __buf;
- std::vformat_to(__buf.out(), __fmt, __args);
- return std::move(__buf).get();
- }
- [[nodiscard]]
- inline wstring
- vformat(wstring_view __fmt, wformat_args __args)
- {
- __format::_Str_sink<wchar_t> __buf;
- std::vformat_to(__buf.out(), __fmt, __args);
- return std::move(__buf).get();
- }
- [[nodiscard]]
- inline string
- vformat(const locale& __loc, string_view __fmt, format_args __args)
- {
- __format::_Str_sink<char> __buf;
- std::vformat_to(__buf.out(), __loc, __fmt, __args);
- return std::move(__buf).get();
- }
- [[nodiscard]]
- inline wstring
- vformat(const locale& __loc, wstring_view __fmt, wformat_args __args)
- {
- __format::_Str_sink<wchar_t> __buf;
- std::vformat_to(__buf.out(), __loc, __fmt, __args);
- return std::move(__buf).get();
- }
- template<typename... _Args>
- [[nodiscard]]
- inline string
- format(format_string<_Args...> __fmt, _Args&&... __args)
- { return std::vformat(__fmt.get(), std::make_format_args(__args...)); }
- template<typename... _Args>
- [[nodiscard]]
- inline wstring
- format(wformat_string<_Args...> __fmt, _Args&&... __args)
- { return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); }
- template<typename... _Args>
- [[nodiscard]]
- inline string
- format(const locale& __loc, format_string<_Args...> __fmt,
- _Args&&... __args)
- {
- return std::vformat(__loc, __fmt.get(),
- std::make_format_args(__args...));
- }
- template<typename... _Args>
- [[nodiscard]]
- inline wstring
- format(const locale& __loc, wformat_string<_Args...> __fmt,
- _Args&&... __args)
- {
- return std::vformat(__loc, __fmt.get(),
- std::make_wformat_args(__args...));
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const char&>
- inline _Out
- format_to(_Out __out, format_string<_Args...> __fmt, _Args&&... __args)
- {
- return std::vformat_to(std::move(__out), __fmt.get(),
- std::make_format_args(__args...));
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const wchar_t&>
- inline _Out
- format_to(_Out __out, wformat_string<_Args...> __fmt, _Args&&... __args)
- {
- return std::vformat_to(std::move(__out), __fmt.get(),
- std::make_wformat_args(__args...));
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const char&>
- inline _Out
- format_to(_Out __out, const locale& __loc, format_string<_Args...> __fmt,
- _Args&&... __args)
- {
- return std::vformat_to(std::move(__out), __loc, __fmt.get(),
- std::make_format_args(__args...));
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const wchar_t&>
- inline _Out
- format_to(_Out __out, const locale& __loc, wformat_string<_Args...> __fmt,
- _Args&&... __args)
- {
- return std::vformat_to(std::move(__out), __loc, __fmt.get(),
- std::make_wformat_args(__args...));
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const char&>
- inline format_to_n_result<_Out>
- format_to_n(_Out __out, iter_difference_t<_Out> __n,
- format_string<_Args...> __fmt, _Args&&... __args)
- {
- __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n);
- std::vformat_to(__sink.out(), __fmt.get(),
- std::make_format_args(__args...));
- return std::move(__sink)._M_finish();
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const wchar_t&>
- inline format_to_n_result<_Out>
- format_to_n(_Out __out, iter_difference_t<_Out> __n,
- wformat_string<_Args...> __fmt, _Args&&... __args)
- {
- __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n);
- std::vformat_to(__sink.out(), __fmt.get(),
- std::make_wformat_args(__args...));
- return std::move(__sink)._M_finish();
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const char&>
- inline format_to_n_result<_Out>
- format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc,
- format_string<_Args...> __fmt, _Args&&... __args)
- {
- __format::_Iter_sink<char, _Out> __sink(std::move(__out), __n);
- std::vformat_to(__sink.out(), __loc, __fmt.get(),
- std::make_format_args(__args...));
- return std::move(__sink)._M_finish();
- }
- template<typename _Out, typename... _Args>
- requires output_iterator<_Out, const wchar_t&>
- inline format_to_n_result<_Out>
- format_to_n(_Out __out, iter_difference_t<_Out> __n, const locale& __loc,
- wformat_string<_Args...> __fmt, _Args&&... __args)
- {
- __format::_Iter_sink<wchar_t, _Out> __sink(std::move(__out), __n);
- std::vformat_to(__sink.out(), __loc, __fmt.get(),
- std::make_wformat_args(__args...));
- return std::move(__sink)._M_finish();
- }
- /// @cond undocumented
- namespace __format
- {
- #if 1
- template<typename _CharT>
- class _Counting_sink final : public _Iter_sink<_CharT, _CharT*>
- {
- public:
- _Counting_sink() : _Iter_sink<_CharT, _CharT*>(nullptr, 0) { }
- [[__gnu__::__always_inline__]]
- size_t
- count() const
- { return this->_M_count + this->_M_used().size(); }
- };
- #else
- template<typename _CharT>
- class _Counting_sink : public _Buf_sink<_CharT>
- {
- size_t _M_count = 0;
- void
- _M_overflow() override
- {
- if (!std::is_constant_evaluated())
- _M_count += this->_M_used().size();
- this->_M_rewind();
- }
- public:
- _Counting_sink() = default;
- [[__gnu__::__always_inline__]]
- size_t
- count() noexcept
- {
- _Counting_sink::_M_overflow();
- return _M_count;
- }
- };
- #endif
- } // namespace __format
- /// @endcond
- template<typename... _Args>
- [[nodiscard]]
- inline size_t
- formatted_size(format_string<_Args...> __fmt, _Args&&... __args)
- {
- __format::_Counting_sink<char> __buf;
- std::vformat_to(__buf.out(), __fmt.get(),
- std::make_format_args(__args...));
- return __buf.count();
- }
- template<typename... _Args>
- [[nodiscard]]
- inline size_t
- formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args)
- {
- __format::_Counting_sink<wchar_t> __buf;
- std::vformat_to(__buf.out(), __fmt.get(),
- std::make_wformat_args(__args...));
- return __buf.count();
- }
- template<typename... _Args>
- [[nodiscard]]
- inline size_t
- formatted_size(const locale& __loc, format_string<_Args...> __fmt,
- _Args&&... __args)
- {
- __format::_Counting_sink<char> __buf;
- std::vformat_to(__buf.out(), __loc, __fmt.get(),
- std::make_format_args(__args...));
- return __buf.count();
- }
- template<typename... _Args>
- [[nodiscard]]
- inline size_t
- formatted_size(const locale& __loc, wformat_string<_Args...> __fmt,
- _Args&&... __args)
- {
- __format::_Counting_sink<wchar_t> __buf;
- std::vformat_to(__buf.out(), __loc, __fmt.get(),
- std::make_wformat_args(__args...));
- return __buf.count();
- }
- #if __cpp_lib_format_ranges
- // [format.range], formatting of ranges
- // [format.range.fmtkind], variable template format_kind
- enum class range_format {
- disabled,
- map,
- set,
- sequence,
- string,
- debug_string
- };
- /// @cond undocumented
- template<typename _Rg>
- constexpr auto format_kind = not defined(format_kind<_Rg>);
- template<typename _Tp>
- consteval range_format
- __fmt_kind()
- {
- using _Ref = ranges::range_reference_t<_Tp>;
- if constexpr (is_same_v<remove_cvref_t<_Ref>, _Tp>)
- return range_format::disabled;
- else if constexpr (requires { typename _Tp::key_type; })
- {
- if constexpr (requires { typename _Tp::mapped_type; })
- {
- using _Up = remove_cvref_t<_Ref>;
- if constexpr (__is_pair<_Up>)
- return range_format::map;
- else if constexpr (__is_specialization_of<_Up, tuple>)
- if constexpr (tuple_size_v<_Up> == 2)
- return range_format::map;
- }
- return range_format::set;
- }
- else
- return range_format::sequence;
- }
- /// @endcond
- /// A constant determining how a range should be formatted.
- template<ranges::input_range _Rg> requires same_as<_Rg, remove_cvref_t<_Rg>>
- constexpr range_format format_kind<_Rg> = __fmt_kind<_Rg>();
- // [format.range.formatter], class template range_formatter
- template<typename _Tp, typename _CharT = char>
- requires same_as<remove_cvref_t<_Tp>, _Tp> && formattable<_Tp, _CharT>
- class range_formatter; // TODO
- /// @cond undocumented
- namespace __format
- {
- // [format.range.fmtdef], class template range-default-formatter
- template<range_format _Kind, ranges::input_range _Rg, typename _CharT>
- struct __range_default_formatter; // TODO
- } // namespace __format
- /// @endcond
- // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr],
- // specializations for maps, sets, and strings
- template<ranges::input_range _Rg, typename _CharT>
- requires (format_kind<_Rg> != range_format::disabled)
- && formattable<ranges::range_reference_t<_Rg>, _CharT>
- struct formatter<_Rg, _CharT>
- : __format::__range_default_formatter<format_kind<_Rg>, _Rg, _CharT>
- { };
- #endif // C++23 formatting ranges
- _GLIBCXX_END_NAMESPACE_VERSION
- } // namespace std
- #endif // C++20
- #endif // _GLIBCXX_FORMAT
|