Sprout.Weed でアンダーバー区切りの2進数をパースをちょっと改良
前回はアンダーバーを取り除いただけでしたが、今回は、
- 4桁区切りで読み込む
- prefix を定義
- 「_」,「.」,「,」 のどれかで区切れる
という感じに改良してみました。
[ソース]
#define SPROUT_CONFIG_SUPPORT_TEMPORARY_CONTAINER_ITERATION #include <sprout/weed.hpp> template<typename Parsed> struct parsed_holder{ constexpr operator bool() const{ return parsed.success(); } template<typename T> constexpr bool operator ==(T&& t) const{ return parsed.attr() == t; } Parsed parsed; }; template<typename Char, std::size_t N, typename Parser> constexpr auto parse(Char const(&str)[N], Parser&& parser) ->parsed_holder<decltype( sprout::weed::parse(str, str+N-1, sprout::forward<Parser>(parser)) )>{ return { sprout::weed::parse(str, str+N-1, sprout::forward<Parser>(parser)) }; } template<typename Parsed> constexpr std::size_t binary_parsed(Parsed&& parsed){ return parsed.success() ? parsed.attr() : 0; } template<typename String> constexpr std::size_t parse_binary(String const& str){ namespace w = sprout::weed; return binary_parsed(w::parse(str.begin(), str.end(), w::bin32 >> w::eoi)); } template<typename Parsed> constexpr std::size_t remove_under_bar_binary_parsed(Parsed&& parsed){ return parsed.success() ? parse_binary(parsed.attr()) : 0; } template< typename Prefix, typename BinTop, typename Bin, typename Delimiter > constexpr std::size_t remove_under_bar_binary(char const* str, std::size_t len, Prefix&& prefix, BinTop&& bin_top, Bin&& bin, Delimiter&& delimiter ){ namespace w = sprout::weed; return remove_under_bar_binary_parsed(w::parse(str, str+len, prefix >> bin_top >> w::repeat(0)[w::lim<7>(delimiter >> bin)] >> w::eoi )); } constexpr std::size_t operator "" _bin(char const* str, std::size_t len){ namespace w = sprout::weed; return remove_under_bar_binary(str, len, w::omit[w::string("0b")|w::string("")], w::repeat(0)[w::lim<4>( w::char_('0')|w::char_('1') )], w::repeat(4)[w::lim<4>( w::char_('0')|w::char_('1') )], w::omit[w::char_('_')|w::char_(',')|w::char_('.')] ); } int main(){ namespace w = sprout::weed; static_assert("0b1111_1111"_bin == 0xff, ""); static_assert( "1111.1111"_bin == 0xff, ""); static_assert("0b0111"_bin == 0x7, ""); static_assert("0b0111_1110"_bin == 0x7e, ""); static_assert("0b1111,1011,0111,1110"_bin == 0xfb7e, ""); static_assert("0b1011"_bin == 0xb, ""); static_assert("0b1011__"_bin == 0, ""); static_assert("0b1111_1111_1111_1111_1111_1111_1111_1111"_bin == 0xffffffff, ""); // 各パーサのテストとか static constexpr auto bit = w::char_('0')|w::char_('1'); static constexpr auto bin = w::repeat(4)[w::lim<4>(bit)]; static constexpr auto bin_top = w::repeat(0)[w::lim<4>(bit)]; static constexpr auto delimiter = w::omit[w::char_('_')]; static constexpr auto prefix = w::omit[w::string("0b")|w::string("")]; static_assert( parse( "1111" , prefix >> bin_top >> w::eoi), ""); static_assert( parse( "0011" , prefix >> bin_top >> w::eoi), ""); static_assert( parse( "111" , prefix >> bin_top >> w::eoi), ""); static_assert( parse( "0b11" , prefix >> bin_top >> w::eoi), ""); static_assert( parse( "0b011" , prefix >> bin_top >> w::eoi), ""); static_assert( parse("0b1011" , prefix >> bin_top >> w::eoi), ""); static_assert( parse( "1111" , prefix >> bin_top >> w::eoi) == "1111" , ""); static_assert( parse("0b1111" , prefix >> bin_top >> w::eoi) == "1111" , ""); static_assert(!parse( "1111_" , prefix >> bin_top >> w::eoi), ""); static_assert(!parse( "3914_" , prefix >> bin_top >> w::eoi), ""); static_assert(!parse( "11111" , prefix >> bin_top >> w::eoi), ""); static constexpr auto bin_parser = prefix >> bin_top >> w::repeat(0)[w::lim<3>(delimiter >> bin)] >> w::eoi; static_assert( parse("1111", bin_parser), ""); static_assert( parse("111", bin_parser), ""); static_assert( parse("1111_1111", bin_parser), ""); static_assert( parse("11_1111", bin_parser), ""); static_assert( parse("0b11_1111", bin_parser), ""); static_assert( parse("1111_0000_1111_1111", bin_parser), ""); static_assert( parse("0b1111_0000_1111_1111", bin_parser) == "1111000011111111", ""); static_assert(!parse("11111", bin_parser), ""); static_assert(!parse("_1111_0000_1111_1111", bin_parser), ""); static_assert(!parse("1111_1111_0000_1111_1111", bin_parser), ""); return 0; }
ちなみに全開に比べてもれなくコンパイル時間が boooooost します。
constexpr な関数内で Sprout.Weed を使おうとすると死んでしまいますね。