text:
#include "uri_common.hpp"
#include <ka/uri/parsing.hpp>
#include <ka/empty.hpp>
#include <boost/range/size.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <gmock/gmock.h>

using namespace ka;
using namespace ka::parse;
using namespace ka::detail_uri;
using namespace ka::detail_uri::parsing;
using namespace testing;
using std::begin; using std::end;

namespace ka
{
namespace parse
{
  template<typename T, typename I>
  void PrintTo(ka::parse::res_t<T, I> const& res, std::ostream* os) {
    auto const empty = ka::empty(res);
    if (empty) {
      *os << "err(";
    }
    else {
      *os << "ok(" << PrintToString(ka::src(res)) << ", ";
    }
    *os << PrintToString(iter(res)) << ")";
  }
} // namespace parse
} // namespace ka

TEST(UriParsingFilter, Succeeds) {
  int const in[] = { 6 };
  auto const expected = *in;
  auto const p = filter([](int i){ return i % 2 == 0; }, parse::symbol);
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingFilter, SucceedsWhenComposed) {
  int const in[] = { 10 };
  auto const expected = *in;
  auto const p = filter([](int i){ return i % 2 == 0; },
                        filter([](int i) { return i % 5 == 0; }, parse::symbol));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingFilter, Fails) {
  auto const t = type_t<int>{};
  int const in[] = { 4 };
  auto const p = filter([](int i){ return i % 3 == 0; }, parse::symbol);
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingLiteral, Succeeds) {
  int const in[] = { 42 };
  auto const expected = *in;
  auto const p = literal(42);
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingLiteral, Fails) {
  auto const t = type_t<int>{};
  int const in[] = { 42 };
  auto const p = literal(15);
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingLiteralsInt, Succeeds) {
  int const in[] = { 4, 12, 22 };
  auto const expected = ka::product(4, 12, 22);
  auto const p = literals(in);
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingLiteralsInt, Fails) {
  auto const t = type_t<ka::product_t<int, int>>{};
  int const in[] = { 4, 12, 22 };
  int const args[] = { 2983, 4387 };
  auto const p = literals(args);
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingLiteralsString, Succeeds) {
  std::string const in = "ab";
  auto const expected = ka::product('a', 'b');
  auto const p = literals("ab");
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingLiteralsString, Fails) {
  auto const t = type_t<ka::product_t<char, char>>{};
  std::string const in = "ab";
  auto const p = literals("ac");
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtLeast, SucceedsOnExactCount) {
  std::string const in = "aaa";
  std::vector<char> const expected = {'a', 'a', 'a'};
  auto const p = at_least(3, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtLeast, SucceedsWhenMore) {
  std::string const in = "aaaaa";
  std::vector<char> const expected = {'a', 'a', 'a', 'a', 'a'};
  auto const p = at_least(3, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtLeast, Fails) {
  auto const t = type_t<std::vector<char>>{};
  std::string const in = "aa";
  auto const p = at_least(3, literal('a'));
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtMost, SucceedsOnExactCount) {
  std::string const in = "aaa";
  std::vector<char> const expected = {'a', 'a', 'a'};
  auto const p = at_most(3, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtMost, SucceedsWhenLess) {
  std::string const in = "aa";
  std::vector<char> const expected = {'a', 'a'};
  auto const p = at_most(3, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtMost, SucceedsWithZero) {
  std::string const in = "";
  std::vector<char> expected;
  auto const p = at_most(3, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingAtMost, SucceedsWithMoreButStops) {
  std::string const in = "aaaa";
  std::vector<char> const expected = {'a', 'a', 'a'};
  auto const p = at_most(3, literal('a'));
  EXPECT_EQ(p(begin(in), end(in)), ok(expected, begin(in) + 3));
}

TEST(UriParsingBetween, Succeeds) {
  std::string const in = "aaa";
  std::vector<char> const expected = {'a', 'a', 'a'};
  auto const p = between(2, 4, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingBetween, SucceedsWhenExactlyLowerBound) {
  std::string const in = "aa";
  std::vector<char> const expected = {'a', 'a'};
  auto const p = between(2, 4, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingBetween, SucceedsWhenExactlyUpperBound) {
  std::string const in = "aaaa";
  std::vector<char> const expected = {'a', 'a', 'a', 'a'};
  auto const p = between(2, 4, literal('a'));
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingBetween, SucceedsWithMoreButStops) {
  std::string const in = "aaaaab";
  std::vector<char> const expected = {'a', 'a', 'a', 'a'};
  auto const p = between(2, 4, literal('a'));
  EXPECT_EQ(p(begin(in), end(in)), ok(expected, begin(in) + 4));
}

TEST(UriParsingBetween, FailsWithLess) {
  auto const t = type_t<std::vector<char>>{};
  std::string const in = "a";
  auto const p = between(2, 4, literal('a'));
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingBetween, FailsWithZero) {
  auto const t = type_t<std::vector<char>>{};
  std::string const in = "b";
  auto const p = between(2, 4, literal('a'));
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

namespace test_uri_parsing {
  /// Generates a string containing all characters that are not in the parameter.
  std::string const all_chars_but(std::string except) {
    static auto const all = []{
      std::string res;
      static_assert(std::numeric_limits<int>::max() > std::numeric_limits<char>::max(), "");
      for (int c = std::numeric_limits<char>::min();
               c <= std::numeric_limits<char>::max();
               ++c) {
        res += static_cast<char>(c);
      }
      return res;
    }();

    std::sort(except.begin(), except.end());
    except.erase(std::unique(except.begin(), except.end()), except.end());
    std::string res;
    std::set_difference(all.begin(), all.end(), except.begin(), except.end(),
                        std::back_inserter(res));
    return res;
  }

  std::string to_string(char c) {
    return std::string(1u, c);
  }

  std::string const alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  std::string const digit = "0123456789";
  std::string const hexdig = "0123456789abcdefABCDEF";
  std::string const unreserved_other = "-._~";
  std::string const gen_delims = ":/?#[]@";
  std::string const sub_delims = "!$&'()*+,;=";
} // namespace test_uri_parsing

using namespace test_uri_parsing;

struct UriParsingAlpha : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(Alpha,
                        UriParsingAlpha,
                        ValuesIn(alpha));

TEST_P(UriParsingAlpha, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::alpha;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingAlphaFailure : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(AllButAlpha,
                        UriParsingAlphaFailure,
                        ValuesIn(all_chars_but(alpha)));

TEST_P(UriParsingAlphaFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::alpha;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingAlphaNum : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(Alpha,
                        UriParsingAlphaNum,
                        ValuesIn(alpha));
INSTANTIATE_TEST_CASE_P(Digit,
                        UriParsingAlphaNum,
                        ValuesIn(digit));

TEST_P(UriParsingAlphaNum, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::alphanum;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingAlphaNumFailure : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(AllButAlphanum,
                        UriParsingAlphaNumFailure,
                        ValuesIn(all_chars_but(alpha + digit)));

TEST_P(UriParsingAlphaNumFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::alphanum;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingDigit : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(Digit,
                        UriParsingDigit,
                        ValuesIn(digit));

TEST_P(UriParsingDigit, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::digit;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingDigitFailure : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(AllButDigit,
                        UriParsingDigitFailure,
                        ValuesIn(all_chars_but(digit)));

TEST_P(UriParsingDigitFailure, Succeeds) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::digit;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingHexdig : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(Hexdig,
                        UriParsingHexdig,
                        ValuesIn(hexdig));

TEST_P(UriParsingHexdig, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::hexdig;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingHexdigFailure : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(AllButHexdig,
                        UriParsingHexdigFailure,
                        ValuesIn(all_chars_but(hexdig)));

TEST_P(UriParsingHexdigFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::hexdig;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingColon, SucceedsOnColon) {
  char const in[] = { ':' };
  auto const expected = *in;
  auto const p = grammar::colon;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingColonFailure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllButColon,
                        UriParsingColonFailure,
                        ValuesIn(all_chars_but(":")));

TEST_P(UriParsingColonFailure, FailsOnOthers) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::colon;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingDbColon, Succeeds) {
  std::string const in = "::";
  auto const expected = ka::product(':', ':');
  auto const p = grammar::dblcolon;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingDblColon, FailsWithOnlyOne) {
  auto const t = type_t<ka::product_t<char, char>>{};
  std::string const in = ":;";
  auto const p = grammar::dblcolon;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingDblColon, Fails) {
  auto const t = type_t<ka::product_t<char, char>>{};
  std::string const in = "a:";
  auto const p = grammar::dblcolon;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingPeriod, SucceedsOnPeriod) {
  char const in[] = { '.' };
  auto const expected = *in;
  auto const p = grammar::period;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingPeriodFailure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllButPeriod,
                        UriParsingPeriodFailure,
                        ValuesIn(all_chars_but(".")));

TEST_P(UriParsingPeriodFailure, FailsOnOthers) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::period;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingSlash, SucceedsOnSlash) {
  char const in[] = { '/' };
  auto const expected = *in;
  auto const p = grammar::slash;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingSlashFailure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllButSlash,
                        UriParsingSlashFailure,
                        ValuesIn(all_chars_but("/")));

TEST_P(UriParsingSlashFailure, FailsOnOthers) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::slash;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingUnreserved : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(Alpha,
                        UriParsingUnreserved,
                        ValuesIn(alpha));
INSTANTIATE_TEST_CASE_P(Digit,
                        UriParsingUnreserved,
                        ValuesIn(digit));
INSTANTIATE_TEST_CASE_P(UnreservedOther,
                        UriParsingUnreserved,
                        ValuesIn(unreserved_other));

TEST_P(UriParsingUnreserved, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::unreserved;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingUnreservedFailure : TestWithParam<char>{};
INSTANTIATE_TEST_CASE_P(AllButUnreserved,
                        UriParsingUnreservedFailure,
                        ValuesIn(all_chars_but(alpha + digit + unreserved_other)));

TEST_P(UriParsingUnreservedFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::unreserved;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

namespace test_uri_parsing {
  namespace pct_encoded {
  std::vector<std::string> all() {
    std::vector<std::string> res;
    for (auto const c1 : hexdig) {
      for (auto const c2 : hexdig) {
        res.push_back(std::string{} + '%' + c1 + c2);
      }
    }
    return res;
  }

  std::string const sub_delims [] = {
    "%21", /* ! */ "%24", /* $ */ "%26", /* & */ "%27", /* ' */ "%28", /* ( */ "%29", /* ) */
    "%2A", /* * */ "%2B", /* + */ "%2C", /* , */ "%3B", /* ; */ "%3D", /* = */
  };
  std::string const gen_delims [] = {
    "%3A", /* : */ "%2F", /* / */ "%3F", /* ? */ "%23", /* # */ "%5B", /* [ */ "%5D", /* ] */
    "%40", /* @ */
  };
  std::pair<std::string, char> const alpha[] = {
    { "%61", 'a' }, { "%62", 'b' }, { "%63", 'c' }, { "%64", 'd' }, { "%65", 'e' }, { "%66", 'f' },
    { "%67", 'g' }, { "%68", 'h' }, { "%69", 'i' }, { "%6A", 'j' }, { "%6B", 'k' }, { "%6C", 'l' },
    { "%6D", 'm' }, { "%6E", 'n' }, { "%6F", 'o' }, { "%70", 'p' }, { "%71", 'q' }, { "%72", 'r' },
    { "%73", 's' }, { "%74", 't' }, { "%75", 'u' }, { "%76", 'v' }, { "%77", 'w' }, { "%78", 'x' },
    { "%79", 'y' }, { "%7A", 'z' }, { "%41", 'A' }, { "%42", 'B' }, { "%43", 'C' }, { "%44", 'D' },
    { "%45", 'E' }, { "%46", 'F' }, { "%47", 'G' }, { "%48", 'H' }, { "%49", 'I' }, { "%4A", 'J' },
    { "%4B", 'K' }, { "%4C", 'L' }, { "%4D", 'M' }, { "%4E", 'N' }, { "%4F", 'O' }, { "%50", 'P' },
    { "%51", 'Q' }, { "%52", 'R' }, { "%53", 'S' }, { "%54", 'T' }, { "%55", 'U' }, { "%56", 'V' },
    { "%57", 'W' }, { "%58", 'X' }, { "%59", 'Y' }, { "%5A", 'Z' },
  };
  std::pair<std::string, char> const numeric[] = {
    { "%30", '0' }, { "%31", '1' }, { "%32", '2' }, { "%33", '3' }, { "%34", '4' }, { "%35", '5' },
    { "%36", '6' }, { "%37", '7' }, { "%38", '8' }, { "%39", '9' },
  };
  std::pair<std::string, char> const other_unreserved[] = {
    { "%2D", '-' }, { "%2E", '.' }, { "%5F", '_' }, { "%7E", '~' },
  };
  std::pair<std::string, char> percent = { "%25", '%' };
  } // namespace pct_encoded
} // namespace test_uri_parsing

struct UriParsingPctEncodedReserved : TestWithParam<std::string> {};
INSTANTIATE_TEST_CASE_P(SubDelims,
                        UriParsingPctEncodedReserved,
                        ValuesIn(pct_encoded::sub_delims));
INSTANTIATE_TEST_CASE_P(GenDelims,
                        UriParsingPctEncodedReserved,
                        ValuesIn(pct_encoded::gen_delims));

TEST_P(UriParsingPctEncodedReserved, CharactersAreLeftEncoded) {
  auto const in = GetParam();
  auto const expected = in;
  auto const p = grammar::pct_encoded;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingPctEncodedUnreserved : TestWithParam<std::pair<std::string, char>> {};
INSTANTIATE_TEST_CASE_P(Alpha,
                        UriParsingPctEncodedUnreserved,
                        ValuesIn(pct_encoded::alpha));
INSTANTIATE_TEST_CASE_P(Numeric,
                        UriParsingPctEncodedUnreserved,
                        ValuesIn(pct_encoded::numeric));
INSTANTIATE_TEST_CASE_P(OtherUnreserved,
                        UriParsingPctEncodedUnreserved,
                        ValuesIn(pct_encoded::other_unreserved));
INSTANTIATE_TEST_CASE_P(Percent,
                        UriParsingPctEncodedUnreserved,
                        Values(pct_encoded::percent));

TEST_P(UriParsingPctEncodedUnreserved, CharactersAreDecoded) {
  auto const param = GetParam();
  auto const in = param.first;
  auto const expected = test_uri_parsing::to_string(param.second);
  auto const p = grammar::pct_encoded;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingPctEncoded, CaseNormalization) {
  std::string const in = "%2f"; // '/' character.
  std::string const expected = "%2F";
  auto const p = grammar::pct_encoded;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingGenDelims : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(GenDelims,
                        UriParsingGenDelims,
                        ValuesIn(gen_delims));

TEST_P(UriParsingGenDelims, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::gen_delims;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingGenDelimsFailure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllButGenDelims,
                        UriParsingGenDelimsFailure,
                        ValuesIn(all_chars_but(gen_delims)));

TEST_P(UriParsingGenDelimsFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::gen_delims;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingSubDelims : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(SubDelims,
                        UriParsingSubDelims,
                        ValuesIn(sub_delims));

TEST_P(UriParsingSubDelims, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::sub_delims;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingSubDelimsFailure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllButSubDelims,
                        UriParsingSubDelimsFailure,
                        ValuesIn(all_chars_but(sub_delims)));

TEST_P(UriParsingSubDelimsFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::sub_delims;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingReserved : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(GenDelims,
                        UriParsingReserved,
                        ValuesIn(gen_delims));
INSTANTIATE_TEST_CASE_P(SubDelims,
                        UriParsingReserved,
                        ValuesIn(sub_delims));

TEST_P(UriParsingReserved, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::reserved;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingReservedFailure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllButReserved,
                        UriParsingReservedFailure,
                        ValuesIn(all_chars_but(gen_delims + sub_delims)));

TEST_P(UriParsingReservedFailure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::reserved;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

namespace test_uri_parsing {
  std::string const pchar_other = ":@";
}

using namespace boost::adaptors;

struct UriParsingPChar : TestWithParam<std::string> {};
INSTANTIATE_TEST_CASE_P(Alpha,
                        UriParsingPChar,
                        ValuesIn(alpha | transformed(test_uri_parsing::to_string)));
INSTANTIATE_TEST_CASE_P(Digit,
                        UriParsingPChar,
                        ValuesIn(digit | transformed(test_uri_parsing::to_string)));
INSTANTIATE_TEST_CASE_P(UnreservedOther,
                        UriParsingPChar,
                        ValuesIn(unreserved_other | transformed(test_uri_parsing::to_string)));
INSTANTIATE_TEST_CASE_P(PctEncodedSubDelims,
                        UriParsingPChar,
                        ValuesIn(pct_encoded::sub_delims));
INSTANTIATE_TEST_CASE_P(PctEncodedGenDelims,
                        UriParsingPChar,
                        ValuesIn(pct_encoded::gen_delims));
INSTANTIATE_TEST_CASE_P(SubDelims,
                        UriParsingPChar,
                        ValuesIn(sub_delims | transformed(test_uri_parsing::to_string)));
INSTANTIATE_TEST_CASE_P(PCharOther,
                        UriParsingPChar,
                        ValuesIn(pchar_other | transformed(test_uri_parsing::to_string)));

TEST_P(UriParsingPChar, Succeeds) {
  auto const in = GetParam();
  auto const expected = in;
  auto const p = grammar::pchar;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingPCharFailure : TestWithParam<std::string> {};
INSTANTIATE_TEST_CASE_P(AllButPChar,
                        UriParsingPCharFailure,
                        ValuesIn(all_chars_but(alpha + digit + unreserved_other + sub_delims +
                                               pchar_other)
                                 | transformed(test_uri_parsing::to_string)));

TEST_P(UriParsingPCharFailure, Fails) {
  auto const t = type_t<std::string>{};
  auto const in = GetParam();
  auto const p = grammar::pchar;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

namespace test_uri_parsing {
  std::string const r1_to_9 = "123456789";
  std::string const r0_to_4 = "01234";
  std::string const r0_to_5 = "012345";
}

struct UriParsingR1To9 : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(Char1To9,
                        UriParsingR1To9,
                        ValuesIn(r1_to_9));

TEST_P(UriParsingR1To9, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::r1_to_9;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingR1To9Failure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllBut1To9,
                        UriParsingR1To9Failure,
                        ValuesIn(all_chars_but(r1_to_9)));

TEST_P(UriParsingR1To9Failure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::r1_to_9;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingR0To4 : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(Char0To4,
                        UriParsingR0To4,
                        ValuesIn(r0_to_4));

TEST_P(UriParsingR0To4, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::r0_to_4;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingR0To4Failure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllBut0To4,
                        UriParsingR0To4Failure,
                        ValuesIn(all_chars_but(r0_to_4)));

TEST_P(UriParsingR0To4Failure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::r0_to_4;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

struct UriParsingR0To5 : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(Char0To5,
                        UriParsingR0To5,
                        ValuesIn(r0_to_5));

TEST_P(UriParsingR0To5, Succeeds) {
  char const in[] = { GetParam() };
  auto const expected = *in;
  auto const p = grammar::r0_to_5;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingR0To5Failure : TestWithParam<char> {};
INSTANTIATE_TEST_CASE_P(AllBut0To5,
                        UriParsingR0To5Failure,
                        ValuesIn(all_chars_but(r0_to_5)));

TEST_P(UriParsingR0To5Failure, Fails) {
  auto const t = type_t<char>{};
  char const in[] = { GetParam() };
  auto const p = grammar::r0_to_5;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

namespace test_uri_parsing {
  std::vector<std::string> dec_octet() {
    std::vector<std::string> res;
    for (int i = 0; i <= 255; ++i) {
      std::ostringstream oss;
      oss << i;
      res.push_back(oss.str());
    }
    return res;
  }

  std::string const not_dec_octet[] = {
    "abc", "ABC", "%25", ""
  };
}

struct UriParsingDecOctet : TestWithParam<std::string> {};
INSTANTIATE_TEST_CASE_P(DecOctet,
                        UriParsingDecOctet,
                        ValuesIn(dec_octet()));

TEST_P(UriParsingDecOctet, Succeeds) {
  auto const in = GetParam();
  auto const expected = in;
  auto const p = grammar::dec_octet;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

struct UriParsingDecOctetFailure : TestWithParam<std::string> {};
INSTANTIATE_TEST_CASE_P(NotDecOctet,
                        UriParsingDecOctetFailure,
                        ValuesIn(not_dec_octet));

TEST_P(UriParsingDecOctetFailure, Fails) {
  auto const t = type_t<std::string>{};
  auto const in = GetParam();
  auto const p = grammar::dec_octet;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingDecOctet, SucceedsOnBeginningOver255) {
  auto const p = grammar::dec_octet;
  {
    std::string const in = "256";
    std::string const expected = "25";
    EXPECT_EQ(p(begin(in), end(in)), ok(expected, begin(in) + 2));
  } {
    std::string const in = "500";
    std::string const expected = "50";
    EXPECT_EQ(p(begin(in), end(in)), ok(expected, begin(in) + 2));
  } {
    std::string const in = "99999";
    std::string const expected = "99";
    EXPECT_EQ(p(begin(in), end(in)), ok(expected, begin(in) + 2));
  } {
    std::string const in = "199999";
    std::string const expected = "199";
    EXPECT_EQ(p(begin(in), end(in)), ok(expected, begin(in) + 3));
  }
}

TEST(UriParsingScheme, CaseNormalization) {
  std::string const in = "CaSeInSeNsItIvE";
  std::string const expected = "caseinsensitive";
  auto const p = grammar::scheme;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

namespace test_uri_parsing {
  std::string const ipv6addresses[] = {
    // The goal here is not to test `ls32`, so we always use the same value for it.
    //                            6( h16 ":" ) ls32
    "a1b2:c3d4:e5f6:a7b8:c9d0:e1f2:a3b4:c5d6",
    //                       "::" 5( h16 ":" ) ls32
       "::c3d4:e5f6:a7b8:c9d0:e1f2:a3b4:c5d6",
    //                [h16 ] "::" 4( h16 ":" ) ls32
            "::e5f6:a7b8:c9d0:e1f2:a3b4:c5d6",
        "c3d4::e5f6:a7b8:c9d0:e1f2:a3b4:c5d6",
    // [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
                 "::a7b8:c9d0:e1f2:a3b4:c5d6",
             "e5f6::a7b8:c9d0:e1f2:a3b4:c5d6",
        "c3d4:e5f6::a7b8:c9d0:e1f2:a3b4:c5d6",
    // [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
                      "::c9d0:e1f2:a3b4:c5d6",
                  "a7b8::c9d0:e1f2:a3b4:c5d6",
             "e5f6:a7b8::c9d0:e1f2:a3b4:c5d6",
        "c3d4:e5f6:a7b8::c9d0:e1f2:a3b4:c5d6",
    // [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
                           "::e1f2:a3b4:c5d6",
                       "c9d0::e1f2:a3b4:c5d6",
                  "a7b8:c9d0::e1f2:a3b4:c5d6",
             "e5f6:a7b8:c9d0::e1f2:a3b4:c5d6",
        "c3d4:e5f6:a7b8:c9d0::e1f2:a3b4:c5d6",
    // [ *4( h16 ":" ) h16 ] "::"              ls32
                                "::a3b4:c5d6",
                            "e1f2::a3b4:c5d6",
                       "c9d0:e1f2::a3b4:c5d6",
                  "a7b8:c9d0:e1f2::a3b4:c5d6",
             "e5f6:a7b8:c9d0:e1f2::a3b4:c5d6",
        "c3d4:e5f6:a7b8:c9d0:e1f2::a3b4:c5d6",
    // [ *5( h16 ":" ) h16 ] "::"              h16
                                     "::c5d6",
                                 "a3b4::c5d6",
                            "e1f2:a3b4::c5d6",
                       "c9d0:e1f2:a3b4::c5d6",
                  "a7b8:c9d0:e1f2:a3b4::c5d6",
             "e5f6:a7b8:c9d0:e1f2:a3b4::c5d6",
        "c3d4:e5f6:a7b8:c9d0:e1f2:a3b4::c5d6",
    // [ *6( h16 ":" ) h16 ] "::"
                                         "::",
                                     "c5d6::",
                                "a3b4:c5d6::",
                           "e1f2:a3b4:c5d6::",
                      "c9d0:e1f2:a3b4:c5d6::",
                 "a7b8:c9d0:e1f2:a3b4:c5d6::",
            "e5f6:a7b8:c9d0:e1f2:a3b4:c5d6::",
       "c3d4:e5f6:a7b8:c9d0:e1f2:a3b4:c5d6::",
  };

  struct Ipv6Address : TestWithParam<std::string> {};
} // namespace test_uri_parsing

using UriParsingIpv6Address = Ipv6Address;
INSTANTIATE_TEST_CASE_P(Ipv6Addresses,
                        UriParsingIpv6Address,
                        ValuesIn(ipv6addresses));

TEST_P(UriParsingIpv6Address, Succeeds) {
  auto const in = GetParam();
  auto const expected = in;
  auto const p = grammar::ipv6address;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingIpv6Address, Fails) {
  auto const t = type_t<std::string>{};
  std::string const in = "abc";
  auto const p = grammar::ipv6address;
  EXPECT_EQ(err(t, begin(in)), p(begin(in), end(in)));
}

TEST(UriParsingHost, CaseNormalization) {
  std::string const in = "SOMEhost";
  std::string const expected = "somehost";
  auto const p = grammar::host;
  EXPECT_EQ(ok(expected, end(in)), p(begin(in), end(in)));
}

TEST(UriParsingLexicallyNormalPath, Basic) {
  EXPECT_EQ("a",       lexically_normal_path("./a"));
  EXPECT_EQ("a/",      lexically_normal_path("./a/"));
  EXPECT_EQ("a/b",     lexically_normal_path("a/./b"));
  EXPECT_EQ("/a",      lexically_normal_path("/./a"));
  EXPECT_EQ("b",       lexically_normal_path("a/../b"));
  EXPECT_EQ("/b",      lexically_normal_path("/a/../b"));
  EXPECT_EQ("c",       lexically_normal_path("a/b/../../c"));
  EXPECT_EQ("a/",      lexically_normal_path("a/.///b/../"));
  EXPECT_EQ("/c/",     lexically_normal_path("///a//.///b/..////../c/////"));
  EXPECT_EQ("/a",      lexically_normal_path("/..//..////a"));
  EXPECT_EQ("/a/",     lexically_normal_path("/..//..////a/"));
  EXPECT_EQ("../../a", lexically_normal_path("..//..////a"));
  EXPECT_EQ("/",       lexically_normal_path("/"));
  EXPECT_EQ(".",       lexically_normal_path("./"));
  EXPECT_EQ("..",      lexically_normal_path("..///"));
  EXPECT_EQ("..",      lexically_normal_path("..///a/../"));
  EXPECT_EQ(".",       lexically_normal_path("a/.."));
  EXPECT_EQ(".",       lexically_normal_path("a/../"));
  EXPECT_EQ(".",       lexically_normal_path("."));
  EXPECT_EQ("",        lexically_normal_path(""));
}

max_stars_repo_name: arntanguy/libqi

max_issues_repo_name: arntanguy/libqi

max_forks_repo_name: arntanguy/libqi


text:
//---------------------------------------------------------------------------//
// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
// See http://kylelutz.github.com/compute for more information.
//---------------------------------------------------------------------------//

#ifndef BOOST_COMPUTE_CONTAINER_MAPPED_VIEW_HPP
#define BOOST_COMPUTE_CONTAINER_MAPPED_VIEW_HPP

#include <cstddef>
#include <exception>

#include <boost/config.hpp>
#include <boost/throw_exception.hpp>

#include <boost/compute/buffer.hpp>
#include <boost/compute/system.hpp>
#include <boost/compute/context.hpp>
#include <boost/compute/command_queue.hpp>
#include <boost/compute/iterator/buffer_iterator.hpp>

namespace boost {
namespace compute {

/// \class mapped_view
/// \brief A mapped view of host memory.
///
/// The mapped_view class simplifies mapping host-memory to a compute
/// device. This allows for host-allocated memory to be used with the
/// Boost.Compute algorithms.
///
/// The following example shows how to map a simple C-array containing
/// data on the host to the device and run the reduce() algorithm to
/// calculate the sum:
///
/// \snippet test/test_mapped_view.cpp reduce
///
/// \see buffer
template<class T>
class mapped_view
{
public:
    typedef T value_type;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef buffer_iterator<T> iterator;
    typedef buffer_iterator<T> const_iterator;

    /// Creates a null mapped_view object.
    mapped_view()
    {
        m_mapped_ptr = 0;
    }

    /// Creates a mapped_view for \p host_ptr with \p n elements. After
    /// constructing a mapped_view the data is available for use by a
    /// compute device. Use the \p unmap() method to make the updated data
    /// available to the host.
    mapped_view(T *host_ptr,
                size_type n,
                const context &context = system::default_context())
        : m_buffer(_make_mapped_buffer(host_ptr, n, context))
    {
        m_mapped_ptr = 0;
    }

    /// Creates a read-only mapped_view for \p host_ptr with \p n elements.
    /// After constructing a mapped_view the data is available for use by a
    /// compute device. Use the \p unmap() method to make the updated data
    /// available to the host.
    mapped_view(const T *host_ptr,
                size_type n,
                const context &context = system::default_context())
        : m_buffer(_make_mapped_buffer(host_ptr, n, context))
    {
        m_mapped_ptr = 0;
    }

    /// Creates a copy of \p other.
    mapped_view(const mapped_view<T> &other)
        : m_buffer(other.m_buffer)
    {
        m_mapped_ptr = 0;
    }

    /// Copies the mapped buffer from \p other.
    mapped_view<T>& operator=(const mapped_view<T> &other)
    {
        if(this != &other){
            m_buffer = other.m_buffer;
            m_mapped_ptr = 0;
        }

        return *this;
    }

    /// Destroys the mapped_view object.
    ~mapped_view()
    {
    }

    /// Returns an iterator to the first element in the mapped_view.
    iterator begin()
    {
        return ::boost::compute::make_buffer_iterator<T>(m_buffer, 0);
    }

    /// Returns a const_iterator to the first element in the mapped_view.
    const_iterator begin() const
    {
        return ::boost::compute::make_buffer_iterator<T>(m_buffer, 0);
    }

    /// Returns a const_iterator to the first element in the mapped_view.
    const_iterator cbegin() const
    {
        return begin();
    }

    /// Returns an iterator to one past the last element in the mapped_view.
    iterator end()
    {
        return ::boost::compute::make_buffer_iterator<T>(m_buffer, size());
    }

    /// Returns a const_iterator to one past the last element in the mapped_view.
    const_iterator end() const
    {
        return ::boost::compute::make_buffer_iterator<T>(m_buffer, size());
    }

    /// Returns a const_iterator to one past the last element in the mapped_view.
    const_iterator cend() const
    {
        return end();
    }

    /// Returns the number of elements in the mapped_view.
    size_type size() const
    {
        return m_buffer.size() / sizeof(T);
    }

    /// Returns the host data pointer.
    T* get_host_ptr()
    {
        return static_cast<T *>(m_buffer.get_info<void *>(CL_MEM_HOST_PTR));
    }

    /// Returns the host data pointer.
    const T* get_host_ptr() const
    {
        return static_cast<T *>(m_buffer.get_info<void *>(CL_MEM_HOST_PTR));
    }

    /// Resizes the mapped_view to \p size elements.
    void resize(size_type size)
    {
        T *old_ptr = get_host_ptr();

        m_buffer = _make_mapped_buffer(old_ptr, size, m_buffer.get_context());
    }

    /// Returns \c true if the mapped_view is empty.
    bool empty() const
    {
        return size() == 0;
    }

    /// Returns the mapped buffer.
    const buffer& get_buffer() const
    {
        return m_buffer;
    }

    /// Maps the buffer into the host address space.
    ///
    /// \see_opencl_ref{clEnqueueMapBuffer}
    void map(cl_map_flags flags, command_queue &queue)
    {
        BOOST_ASSERT(m_mapped_ptr == 0);

        m_mapped_ptr = queue.enqueue_map_buffer(
            m_buffer, flags, 0, m_buffer.size()
        );
    }

    /// Maps the buffer into the host address space for reading and writing.
    ///
    /// Equivalent to:
    /// \code
    /// map(CL_MAP_READ | CL_MAP_WRITE, queue);
    /// \endcode
    void map(command_queue &queue)
    {
        map(CL_MAP_READ | CL_MAP_WRITE, queue);
    }

    /// Unmaps the buffer from the host address space.
    ///
    /// \see_opencl_ref{clEnqueueUnmapMemObject}
    void unmap(command_queue &queue)
    {
        BOOST_ASSERT(m_mapped_ptr != 0);

        queue.enqueue_unmap_buffer(m_buffer, m_mapped_ptr);

        m_mapped_ptr = 0;
    }

private:
    /// \internal_
    static buffer _make_mapped_buffer(T *host_ptr,
                                      size_t n,
                                      const context &context)
    {
        return buffer(
            context,
            n * sizeof(T),
            buffer::read_write | buffer::use_host_ptr,
            host_ptr
        );
    }

    /// \internal_
    static buffer _make_mapped_buffer(const T *host_ptr,
                                      size_t n,
                                      const context &context)
    {
        return buffer(
            context,
            n * sizeof(T),
            buffer::read_only | buffer::use_host_ptr,
            const_cast<void *>(static_cast<const void *>(host_ptr))
        );
    }

private:
    buffer m_buffer;
    void *m_mapped_ptr;
};

} // end compute namespace
} // end boost namespace

#endif // BOOST_COMPUTE_CONTAINER_MAPPED_VIEW_HPP

ext: hpp

max_stars_repo_name: bastiankoe/compute

max_issues_repo_name: bastiankoe/compute

max_forks_repo_name: bastiankoe/compute


text:
#ifndef TM_KIT_BASIC_GENERIC_IO_STREAM_IMPORTER_EXPORTER_HPP_
#define TM_KIT_BASIC_GENERIC_IO_STREAM_IMPORTER_EXPORTER_HPP_

#include <type_traits>
#include <iostream>
#include <chrono>
#include <cstddef>
#include <vector>
#include <cstring>
#include <string_view>
#include <boost/endian/conversion.hpp>
#include <tm_kit/infra/RealTimeApp.hpp>
#include <tm_kit/infra/SinglePassIterationApp.hpp>
#include <tm_kit/infra/TopDownSinglePassIterationApp.hpp>
#include <tm_kit/infra/TraceNodesComponent.hpp>
#include <tm_kit/infra/BasicWithTimeApp.hpp>
#include <tm_kit/basic/ByteDataWithTopicRecordFile.hpp>
#include <tm_kit/basic/ByteData.hpp>

namespace dev { namespace cd606 { namespace tm { namespace basic {

    template <class App>
    class GenericIOStreamImporterExporter {
    };

    template <class App>
    struct OneGenericIStreamImporterSpec {
        std::shared_ptr<std::istream> stream;
        std::function<typename App::Duration(typename App::TimePoint const &)> delayer;
    };
    template <class App>
    using GenericIStreamImporterSpec = std::vector<OneGenericIStreamImporterSpec<App>>;

    class GenericIOStreamImporterExporterHelper {
    private:
        template <class App, class T, class DataComparer=std::less<T>>
        struct QueueItem {
            typename App::TimePoint tp;
            T data;
            OneGenericIStreamImporterSpec<App> *spec;
            DataComparer *comparer;
            std::size_t index;

            bool operator<(QueueItem const &item) const {
                if (this == &item) {
                    return false;
                }
                if (tp > item.tp) {
                    return true;
                }
                if (tp < item.tp) {
                    return false;
                }
                if ((*comparer)(item.data, data)) {
                    return true;
                }
                if ((*comparer)(data, item.data)) {
                    return false;
                }
                return (index > item.index);
            }
        };
    public:
        template <class App, class T, class DataComparer=std::less<T>>
        using Queue = std::priority_queue<QueueItem<App,T,DataComparer>>;

        template <class App, class T, class Reader, class DataComparer>
        static void startQueue(typename App::EnvironmentType *env, Queue<App,T,DataComparer> &queue, GenericIStreamImporterSpec<App> &spec, Reader &reader, DataComparer &comparer) {
            for (auto ii=0; ii<spec.size(); ++ii) {
                reader.start(env, *(spec[ii].stream));
                std::optional<std::tuple<typename App::TimePoint,T>> data = reader.readOne(env, *(spec[ii].stream));
                if (data) {
                    auto tp = std::get<0>(*data);
                    if (spec[ii].delayer) {
                        tp += spec[ii].delayer(tp);
                    }
                    queue.push(
                        QueueItem<App,T,DataComparer> {
                            tp, std::move(std::get<1>(*data)), &(spec[ii]), &comparer, ii
                        }
                    );
                }
            }
        }
        template <class App, class T, class Reader, class DataComparer>
        static typename App::template Data<T> stepQueue(typename App::EnvironmentType *env, Queue<App,T,DataComparer> &queue, Reader &reader) {
            if (queue.empty()) {
                return std::nullopt;
            }
            auto item = queue.top();
            queue.pop();
            std::optional<std::tuple<typename App::TimePoint,T>> data = reader.readOne(env, *(item.spec->stream));
            if (data) {
                auto tp = std::get<0>(*data);
                if (item.spec->delayer) {
                    tp += item.spec->delayer(tp);
                }
                queue.push(
                    QueueItem<App,T,DataComparer> {
                        tp, std::move(std::get<1>(*data)), item.spec, item.comparer, item.index
                    }
                );
            }
            return typename App::template InnerData<T> {
                env
                , {
                    item.tp
                    , item.data
                    , queue.empty()
                }
            };
        }

        template <std::size_t BufferSize>
        class BufferedReader {
        private:
            std::unique_ptr<char[]> buf_[2];
            int bufIndex_;
            std::size_t bufPos_[2], bufEndPos_[2];
            bool fileEof_;
            bool done_;
        public:
            BufferedReader()
                : buf_{
                    std::make_unique<char[]>(BufferSize)
                    , std::make_unique<char[]>(BufferSize)
                }
                , bufIndex_(0)
                , bufPos_{0,0}
                , bufEndPos_{0,0}
                , fileEof_(false)
                , done_(false)
            {}
            ~BufferedReader() = default;
            BufferedReader(BufferedReader &&) = default;
            BufferedReader &operator=(BufferedReader &&) = default;
            std::string_view read(std::istream &is, std::size_t n) {
                if (n > BufferSize) {
                    return {nullptr, 0};
                }
                if (done_) {
                    return {nullptr, 0};
                }
                if (bufEndPos_[bufIndex_] < bufPos_[bufIndex_]+n) {
                    std::size_t needed = bufPos_[bufIndex_]+n-bufEndPos_[bufIndex_];
                    if (fileEof_) {
                        done_ = true;
                        return {nullptr,0};
                    }
                    is.read(buf_[1-bufIndex_].get(), BufferSize);
                    bufEndPos_[1-bufIndex_] = is.gcount();
                    fileEof_ = (bufEndPos_[1-bufIndex_] != BufferSize);

                    if (bufEndPos_[1-bufIndex_] < needed) {
                        done_ = true;
                        return {nullptr,0};
                    }
                    std::memmove(buf_[bufIndex_].get(), buf_[bufIndex_].get()+bufPos_[bufIndex_], n-needed);
                    std::memcpy(buf_[bufIndex_].get()+(n-needed), buf_[1-bufIndex_].get(), needed);
                    bufPos_[bufIndex_] = 0;
                    bufEndPos_[bufIndex_] = 0;
                    bufPos_[1-bufIndex_] = needed;
                    bufIndex_ = 1-bufIndex_;
                    return {buf_[1-bufIndex_].get(), n};
                } else {
                    bufPos_[bufIndex_] += n;
                    return {buf_[bufIndex_].get()+bufPos_[bufIndex_]-n,n};
                }
            }
        };
    };

    template <class Env>
    class GenericIOStreamImporterExporter<infra::BasicWithTimeApp<Env>> {
    public:
        template <class T, class Reader, class DataComparer=std::less<T>>
        static std::shared_ptr<typename infra::BasicWithTimeApp<Env>::template Importer<T>>
        createImporter(
            GenericIStreamImporterSpec<infra::BasicWithTimeApp<Env>> const &spec
            , Reader &&reader
            , DataComparer &&dataComparer = DataComparer {}
        ) {
            return infra::BasicWithTimeApp<Env>::template vacuousImporter<T>();
        }

        template <class T, class Writer>
        static std::shared_ptr<typename infra::BasicWithTimeApp<Env>::template Exporter<T>>
        createExporter(std::ostream &os, Writer &&writer, bool separateThread=false) {
            return infra::BasicWithTimeApp<Env>::template trivialExporter<T>();
        }
    };

    template <class Env>
    class GenericIOStreamImporterExporter<infra::RealTimeApp<Env>> {
    public:
        template <class T, class Reader, class DataComparer=std::less<T>>
        static std::shared_ptr<typename infra::RealTimeApp<Env>::template Importer<T>>
        createImporter(
            GenericIStreamImporterSpec<infra::RealTimeApp<Env>> const &spec
            , Reader &&reader
            , DataComparer &&dataComparer = DataComparer {}
        ) {
            class LocalI : public infra::RealTimeApp<Env>::template AbstractImporter<T>, public virtual infra::IControllableNode<Env> {
            private:
                GenericIStreamImporterSpec<infra::RealTimeApp<Env>> spec_;
                Reader reader_;
                DataComparer dataComparer_;
                GenericIOStreamImporterExporterHelper::Queue<infra::RealTimeApp<Env>,T,DataComparer> queue_;

                Env *env_;
                std::thread th_;
                std::atomic<bool> running_;

                void run() {
                    GenericIOStreamImporterExporterHelper::template startQueue<infra::SinglePassIterationApp<Env>,T,Reader,DataComparer>(
                        env_, queue_, spec_, reader_, dataComparer_
                    );
                    while (running_) {
                        TM_INFRA_IMPORTER_TRACER(env_);
                        auto t = env_->now();
                        while (true) {
                            auto ret = GenericIOStreamImporterExporterHelper::template stepQueue<infra::SinglePassIterationApp<Env>,T,Reader,DataComparer>(
                                env_, queue_, reader_
                            );
                            if (!ret) {
                                running_ = false;
                                break;
                            }

                            if (ret->timedData.timePoint < t) {
                                if (ret->timedData.timePoint >= t-std::chrono::seconds(1)) {
                                    this->publish(std::move(*ret));
                                } else {
                                    continue;
                                }
                            } else if (ret->timedData.timePoint == t) {
                                this->publish(std::move(*ret));
                            } else {
                                env_->sleepFor(ret->timedData.timePoint-t);
                                this->publish(std::move(*ret));
                                break;
                            }
                        }
                    }
                }
            public:
                LocalI(
                    GenericIStreamImporterSpec<infra::RealTimeApp<Env>> const &spec
                    , Reader &&reader
                    , DataComparer &&dataComparer
                ) :
                    spec_(spec)
                    , reader_(std::move(reader))
                    , dataComparer_(std::move(dataComparer))
                    , queue_()
                    , env_(nullptr)
                    , th_()
                    , running_(false)
                {}
                virtual void start(Env *env) override final {
                    env_ = env;
                    running_ = true;
                    th_ = std::thread(&LocalI::run, this);
                    th_.detach();
                }
                virtual void control(Env *env, std::string const &command, std::vector<std::string> const &params) override final {
                    if (command == "stop") {
                        running_ = false;
                        try {
                            th_.join();
                        } catch (...) {
                        }
                    }
                }
            };
            return infra::RealTimeApp<Env>::template importer<T>(new LocalI(spec, std::move(reader), std::move(dataComparer)));
        }

        template <class T, class Reader>
        static std::shared_ptr<typename infra::RealTimeApp<Env>::template Importer<T>>
        createImporter(
            std::shared_ptr<std::istream> const &stream
            , Reader &&reader = Reader {}
        ) {
            class LocalI : public infra::RealTimeApp<Env>::template AbstractImporter<T>, public virtual infra::IControllableNode<Env> {
            private:
                std::shared_ptr<std::istream> stream_;
                Reader reader_;

                Env *env_;
                std::thread th_;
                std::atomic<bool> running_;

                void run() {
                    reader_.start(env_, *stream_);
                    std::optional<std::tuple<typename infra::RealTimeApp<Env>::TimePoint,T>> data = reader_.readOne(env_, *stream_);
                    if (data) {
                        while (data && running_) {
                            TM_INFRA_IMPORTER_TRACER(env_);
                            std::optional<std::tuple<typename infra::RealTimeApp<Env>::TimePoint,T>> newData = reader_.readOne(env_, *stream_);
                            auto t = env_->now();
                            auto dataT = std::get<0>(*data);
                            if (dataT < t) {
                                if (dataT >= t-std::chrono::seconds(1)) {
                                    this->publish(typename infra::RealTimeApp<Env>::template InnerData<T> {
                                        env_
                                        , {
                                            dataT
                                            , std::move(std::get<1>(*data))
                                            , !((bool) newData)
                                        }
                                    });
                                }
                            } else if (dataT == t) {
                                this->publish(typename infra::RealTimeApp<Env>::template InnerData<T> {
                                    env_
                                    , {
                                        dataT
                                        , std::move(std::get<1>(*data))
                                        , !((bool) newData)
                                    }
                                });
                            } else {
                                env_->sleepFor(dataT-t);
                                this->publish(typename infra::RealTimeApp<Env>::template InnerData<T> {
                                    env_
                                    , {
                                        dataT
                                        , std::move(std::get<1>(*data))
                                        , !((bool) newData)
                                    }
                                });
                            }
                            data = std::move(newData);
                        }
                    }
                }
            public:
                LocalI(
                    std::shared_ptr<std::istream> const &stream
                    , Reader &&reader
                ) :
                    stream_(stream)
                    , reader_(std::move(reader))
                    , env_(nullptr)
                    , th_()
                    , running_(false)
                {}
                virtual void start(Env *env) override final {
                    env_ = env;
                    running_ = true;
                    th_ = std::thread(&LocalI::run, this);
                    th_.detach();
                }
                virtual void control(Env *env, std::string const &command, std::vector<std::string> const &params) override final {
                    if (command == "stop") {
                        running_ = false;
                        try {
                            th_.join();
                        } catch (...) {
                        }
                    }
                }
            };
            return infra::RealTimeApp<Env>::template importer<T>(new LocalI(stream, std::move(reader)));
        }

        template <class T, class Writer>
        static std::shared_ptr<typename infra::RealTimeApp<Env>::template Exporter<T>>
        createExporter(std::ostream &os, Writer &&writer, bool separateThread=false) {
            class LocalENonThreaded final : public infra::RealTimeApp<Env>::template AbstractExporter<T> {
            private:
                std::ostream *os_;
                Writer writer_;
            public:
                LocalENonThreaded(std::ostream &os, Writer &&writer) : os_(&os), writer_(std::move(writer)) {}
                virtual void start(Env *env) override final {
                    writer_.start(env, *os_);
                }
                virtual void handle(typename infra::RealTimeApp<Env>::template InnerData<T> &&d) override final {
                    TM_INFRA_EXPORTER_TRACER(d.environment);
                    writer_.writeOne(d.environment, *os_, std::move(d.timedData));
                    os_->flush();
                }
            };
            class LocalEThreaded final : public infra::RealTimeApp<Env>::template AbstractExporter<T>, public infra::RealTimeAppComponents<Env>::template ThreadedHandler<ByteDataWithTopic> {
            private:
                std::ostream *os_;
                Writer writer_;
            public:
            #ifdef _MSC_VER
                LocalEThreaded(std::ostream &os, Writer &&writer) : os_(&os), writer_(std::move(writer)) {
            #else
                LocalEThreaded(std::ostream &os, Writer &&writer) : infra::RealTimeAppComponents<Env>::template ThreadedHandler<T>(), os_(&os), writer_(std::move(writer)) {
            #endif
                    this->startThread();
                }
                virtual void start(Env *env) override final {
                    writer_.start(env, *os_);
                }
            private:
                virtual void actuallyHandle(typename infra::RealTimeApp<Env>::template InnerData<T> &&d) override final {
                    TM_INFRA_EXPORTER_TRACER(d.environment);
                    writer_.writeOne(d.environment, *os_, std::move(d.timedData));
                    os_->flush();
                }
            };
            if (separateThread) {
                return infra::RealTimeApp<Env>::template exporter(new LocalEThreaded(os, std::move(writer)));
            } else {
                return infra::RealTimeApp<Env>::template exporter(new LocalENonThreaded(os, std::move(writer)));
            }
        }
    };

    template <class Env>
    class GenericIOStreamImporterExporter<infra::SinglePassIterationApp<Env>> {
    public:
        template <class T, class Reader, class DataComparer=std::less<T>>
        static std::shared_ptr<typename infra::SinglePassIterationApp<Env>::template Importer<T>>
        createImporter(
            GenericIStreamImporterSpec<infra::SinglePassIterationApp<Env>> const &spec
            , Reader &&reader
            , DataComparer &&dataComparer = DataComparer {}
        ) {
            class LocalI final : public infra::SinglePassIterationApp<Env>::template AbstractImporter<T> {
            private:
                GenericIStreamImporterSpec<infra::SinglePassIterationApp<Env>> spec_;
                Reader reader_;
                DataComparer dataComparer_;
                GenericIOStreamImporterExporterHelper::Queue<infra::SinglePassIterationApp<Env>,T,DataComparer> queue_;

                Env *env_;
            public:
                LocalI(
                    GenericIStreamImporterSpec<infra::SinglePassIterationApp<Env>> const &spec
                    , Reader &&reader
                    , DataComparer &&dataComparer
                ) :
                    spec_(spec)
                    , reader_(std::move(reader))
                    , dataComparer_(std::move(dataComparer))
                    , queue_()
                    , env_(nullptr)
                {}
                virtual void start(Env *env) override final {
                    env_ = env;
                    GenericIOStreamImporterExporterHelper::template startQueue<infra::SinglePassIterationApp<Env>,T,Reader,DataComparer>(
                        env_, queue_, spec_, reader_, dataComparer_
                    );
                }
                virtual typename infra::SinglePassIterationApp<Env>::template Data<T>
                generate(T const *notUsed=nullptr) override final {
                    TM_INFRA_IMPORTER_TRACER(env_);
                    return GenericIOStreamImporterExporterHelper::template stepQueue<infra::SinglePassIterationApp<Env>,T,Reader,DataComparer>(
                        env_, queue_, reader_
                    );
                }
            };
            return infra::SinglePassIterationApp<Env>::template importer<T>(new LocalI(spec, std::move(reader), std::move(dataComparer)));
        }

        template <class T, class Reader>
        static std::shared_ptr<typename infra::SinglePassIterationApp<Env>::template Importer<T>>
        createImporter(
            std::shared_ptr<std::istream> const &stream
            , Reader &&reader = Reader {}
        ) {
            class LocalI final : public infra::SinglePassIterationApp<Env>::template AbstractImporter<T> {
            private:
                std::shared_ptr<std::istream> stream_;
                Reader reader_;
                std::optional<std::tuple<typename infra::SinglePassIterationApp<Env>::TimePoint,T>> data_;

                Env *env_;
            public:
                LocalI(
                    std::shared_ptr<std::istream> const &stream
                    , Reader &&reader
                ) :
                    stream_(stream)
                    , reader_(std::move(reader))
                    , data_(std::nullopt)
                    , env_(nullptr)
                {}
                virtual void start(Env *env) override final {
                    env_ = env;
                    reader_.start(env_, *stream_);
                    data_ = reader_.readOne(env_, *stream_);
                }
                virtual typename infra::SinglePassIterationApp<Env>::template Data<T>
                generate(T const *notUsed=nullptr) override final {
                    TM_INFRA_IMPORTER_TRACER(env_);
                    if (!data_) {
                        return std::nullopt;
                    }
                    std::optional<std::tuple<typename infra::SinglePassIterationApp<Env>::TimePoint,T>> newData = reader_.readOne(env_, *stream_);
                    auto ret = typename infra::SinglePassIterationApp<Env>::template InnerData<T> {
                        env_
                        , {
                            std::get<0>(*data_)
                            , std::move(std::get<1>(*data_))
                            , !((bool) newData)
                        }
                    };
                    data_ = std::move(newData);
                    return std::move(ret);
                }
            };
            return infra::SinglePassIterationApp<Env>::template importer<T>(new LocalI(stream, std::move(reader)));
        }

        template <class T, class Writer>
        static std::shared_ptr<typename infra::SinglePassIterationApp<Env>::template Exporter<T>>
        createExporter(std::ostream &os, Writer &&writer, bool separateThread=false) {
            class LocalE final : public infra::SinglePassIterationApp<Env>::template AbstractExporter<T> {
            private:
                std::ostream *os_;
                Writer writer_;
            public:
                LocalE(std::ostream &os, Writer &&writer) : os_(&os), writer_(std::move(writer)) {}
                virtual void start(Env *env) override final {
                    writer_.start(env, *os_);
                }
                virtual void handle(typename infra::SinglePassIterationApp<Env>::template InnerData<T> &&d) override final {
                    TM_INFRA_EXPORTER_TRACER(d.environment);
                    writer_.writeOne(d.environment, *os_, std::move(d.timedData));
                    os_->flush();
                }
            };
            return infra::SinglePassIterationApp<Env>::template exporter(new LocalE(os, std::move(writer)));
        }
    };

    template <class Env>
    class GenericIOStreamImporterExporter<infra::TopDownSinglePassIterationApp<Env>> {
    public:
        template <class T, class Reader, class DataComparer=std::less<T>>
        static std::shared_ptr<typename infra::TopDownSinglePassIterationApp<Env>::template Importer<T>>
        createImporter(
            GenericIStreamImporterSpec<infra::TopDownSinglePassIterationApp<Env>> const &spec
            , Reader &&reader
            , DataComparer &&dataComparer = DataComparer {}
        ) {
            class LocalI final : public infra::TopDownSinglePassIterationApp<Env>::template AbstractImporter<T> {
            private:
                GenericIStreamImporterSpec<infra::TopDownSinglePassIterationApp<Env>> spec_;
                Reader reader_;
                DataComparer dataComparer_;
                GenericIOStreamImporterExporterHelper::Queue<infra::TopDownSinglePassIterationApp<Env>,T,DataComparer> queue_;

                Env *env_;
            public:
                LocalI(
                    GenericIStreamImporterSpec<infra::TopDownSinglePassIterationApp<Env>> const &spec
                    , Reader &&reader
                    , DataComparer &&dataComparer
                ) :
                    spec_(spec)
                    , reader_(std::move(reader))
                    , dataComparer_(std::move(dataComparer))
                    , queue_()
                    , env_(nullptr)
                {}
                virtual void start(Env *env) override final {
                    env_ = env;
                    GenericIOStreamImporterExporterHelper::template startQueue<infra::TopDownSinglePassIterationApp<Env>,T,Reader,DataComparer>(
                        env_, queue_, spec_, reader_, dataComparer_
                    );
                }
                virtual std::tuple<bool, typename infra::TopDownSinglePassIterationApp<Env>::template Data<T>>
                generate(T const *notUsed=nullptr) override final {
                    TM_INFRA_IMPORTER_TRACER(env_);
                    auto ret = GenericIOStreamImporterExporterHelper::template stepQueue<infra::TopDownSinglePassIterationApp<Env>,T,Reader,DataComparer>(
                        env_, queue_, reader_
                    );
                    if (!ret) {
                        return {false, std::nullopt};
                    }
                    return {!(ret->timedData.finalFlag), std::move(ret)};
                }
            };
            return infra::TopDownSinglePassIterationApp<Env>::template importer<T>(new LocalI(spec, std::move(reader), std::move(dataComparer)));
        }

        template <class T, class Reader>
        static std::shared_ptr<typename infra::TopDownSinglePassIterationApp<Env>::template Importer<T>>
        createImporter(
            std::shared_ptr<std::istream> const &stream
            , Reader &&reader = Reader {}
        ) {
            class LocalI final : public infra::TopDownSinglePassIterationApp<Env>::template AbstractImporter<T> {
            private:
                std::shared_ptr<std::istream> stream_;
                Reader reader_;
                std::optional<std::tuple<typename infra::TopDownSinglePassIterationApp<Env>::TimePoint,T>> data_;

                Env *env_;
            public:
                LocalI(
                    std::shared_ptr<std::istream> const &stream
                    , Reader &&reader
                ) :
                    stream_(stream)
                    , reader_(std::move(reader))
                    , data_(std::nullopt)
                    , env_(nullptr)
                {}
                virtual void start(Env *env) override final {
                    env_ = env;
                    reader_.start(env_, *stream_);
                    data_ = reader_.readOne(env_, *stream_);
                }
                virtual std::tuple<bool, typename infra::TopDownSinglePassIterationApp<Env>::template Data<T>>
                generate(T const *notUsed=nullptr) override final {
                    TM_INFRA_IMPORTER_TRACER(env_);
                    if (!data_) {
                        return {false, std::nullopt};
                    }
                    std::optional<std::tuple<typename infra::TopDownSinglePassIterationApp<Env>::TimePoint,T>> newData = reader_.readOne(env_, *stream_);
                    auto ret = typename infra::SinglePassIterationApp<Env>::template InnerData<T> {
                        env_
                        , {
                            std::get<0>(*data_)
                            , std::move(std::get<1>(*data_))
                            , !((bool) newData)
                        }
                    };
                    data_ = std::move(newData);
                    return {!(ret.timedData.finalFlag), {std::move(ret)}};
                }
            };
            return infra::TopDownSinglePassIterationApp<Env>::template importer<T>(new LocalI(stream, std::move(reader)));
        }

        template <class T, class Writer>
        static std::shared_ptr<typename infra::TopDownSinglePassIterationApp<Env>::template Exporter<T>>
        createExporter(std::ostream &os, Writer &&writer, bool separateThread=false) {
            class LocalE final : public infra::TopDownSinglePassIterationApp<Env>::template AbstractExporter<T> {
            private:
                std::ostream *os_;
                Writer writer_;
            public:
                LocalE(std::ostream &os, Writer &&writer) : os_(&os), writer_(std::move(writer)) {}
                virtual void start(Env *env) override final {
                    writer_.start(env, *os_);
                }
                virtual void handle(typename infra::TopDownSinglePassIterationApp<Env>::template InnerData<T> &&d) override final {
                    TM_INFRA_EXPORTER_TRACER(d.environment);
                    writer_.writeOne(d.environment, *os_, std::move(d.timedData));
                    os_->flush();
                }
            };
            return infra::TopDownSinglePassIterationApp<Env>::template exporter(new LocalE(os, std::move(writer)));
        }
    };

    template <class T, class SizeType=std::size_t>
    class SimpleSerializingWriter {
    public:
        template <class Env>
        static void start(Env *env, std::ostream &os) {}
        template <class Env, class TimePoint>
        static void writeOne(Env *env, std::ostream &os, infra::WithTime<T, TimePoint> &&data) {
            if constexpr (bytedata_utils::DirectlySerializableChecker<T>::IsDirectlySerializable()) {
                std::string s = bytedata_utils::RunSerializer<T>::apply(data.value);
                SizeType l = boost::endian::native_to_little<SizeType>(s.length());
                os.write(reinterpret_cast<char *>(&l), sizeof(SizeType));
                os.write(s.data(), s.length());
            } else {
                std::string s = bytedata_utils::RunCBORSerializer<T>::apply(data.value);
                SizeType l = boost::endian::native_to_little<SizeType>(s.length());
                os.write(reinterpret_cast<char *>(&l), sizeof(SizeType));
                os.write(s.data(), s.length());
            }
        }
    };
    template <class T, class TimeExtractor, class SizeType=std::size_t, std::size_t BufferSize=4*1024*1024>
    class SimpleDeserializingReader {
    private:
        TimeExtractor timeExtractor_;
        GenericIOStreamImporterExporterHelper::BufferedReader<BufferSize> bufferedReader_;
    public:
        SimpleDeserializingReader(TimeExtractor &&timeExtractor = TimeExtractor {}) : timeExtractor_(std::move(timeExtractor)), bufferedReader_() {}
        template <class Env>
        static void start(Env *env, std::istream &is) {}
        template <class Env>
        std::optional<std::tuple<typename Env::TimePointType, T>> readOne(Env *env, std::istream &is) {
            auto sizeBuf = bufferedReader_.read(is, sizeof(SizeType));
            if (sizeBuf.length() == 0) {
                return std::nullopt;
            }
            SizeType l;
            std::memcpy(&l, sizeBuf.data(), sizeof(SizeType));
            l = boost::endian::little_to_native<SizeType>(l);
            auto dataBuf = bufferedReader_.read(is, l);
            if (dataBuf.length() == 0) {
                return std::nullopt;
            }
            if constexpr (bytedata_utils::DirectlySerializableChecker<T>::IsDirectlySerializable()) {
                auto ret = bytedata_utils::RunDeserializer<T>::apply(dataBuf);
                if (!ret) {
                    return std::nullopt;
                }
                auto tp = timeExtractor_(*ret);
                return std::tuple<typename Env::TimePointType, T> {
                    tp
                    , std::move(*ret)
                };
            } else {
                auto ret = bytedata_utils::RunCBORDeserializer<T>::apply(dataBuf, 0);
                if (!ret) {
                    return std::nullopt;
                }
                if (std::get<1>(*ret) != l) {
                    return std::nullopt;
                }
                auto tp = timeExtractor_(std::get<0>(*ret));
                return std::tuple<typename Env::TimePointType, T> {
                    tp
                    , std::move(std::get<0>(*ret))
                };
            }
        }
    };

    template <class T, class TimeWriter, class SizeType=std::size_t>
    class SimpleSerializingWriterWithTime {
    private:
        TimeWriter timeWriter_;
    public:
        SimpleSerializingWriterWithTime(TimeWriter &&timeWriter = TimeWriter {}) : timeWriter_(std::move(timeWriter)) {}
        template <class Env>
        static void start(Env *env, std::ostream &os) {}
        template <class Env, class TimePoint>
        void writeOne(Env *env, std::ostream &os, infra::WithTime<T, TimePoint> &&data) {
            timeWriter_(env, os, data.timePoint);
            if constexpr (bytedata_utils::DirectlySerializableChecker<T>::IsDirectlySerializable()) {
                std::string s = bytedata_utils::RunSerializer<T>::apply(data.value);
                SizeType l = boost::endian::native_to_little<SizeType>(s.length());
                os.write(reinterpret_cast<char *>(&l), sizeof(SizeType));
                os.write(s.data(), s.length());
            } else {
                std::string s = bytedata_utils::RunCBORSerializer<T>::apply(data.value);
                SizeType l = boost::endian::native_to_little<SizeType>(s.length());
                os.write(reinterpret_cast<char *>(&l), sizeof(SizeType));
                os.write(s.data(), s.length());
            }
        }
    };
    template <class T, class TimeReader, class SizeType=std::size_t, std::size_t BufferSize=4*1024*1024>
    class SimpleDeserializingReaderWithTime {
    private:
        TimeReader timeReader_;
        GenericIOStreamImporterExporterHelper::BufferedReader<BufferSize> bufferedReader_;
    public:
        SimpleDeserializingReaderWithTime(TimeReader &&timeReader = TimeReader {}) : timeReader_(std::move(timeReader)), bufferedReader_() {}
        template <class Env>
        static void start(Env *env, std::istream &is) {}
        template <class Env>
        std::optional<std::tuple<typename Env::TimePointType, T>> readOne(Env *env, std::istream &is) {
            auto timeBuf = bufferedReader_.read(is, TimeReader::TimeSize);
            if (timeBuf.length() == 0) {
                return std::nullopt;
            }
            std::optional<typename Env::TimePointType> tp = timeReader_(env, timeBuf);
            if (!tp) {
                return std::nullopt;
            }
            auto sizeBuf = bufferedReader_.read(is, sizeof(SizeType));
            if (sizeBuf.length() == 0) {
                return std::nullopt;
            }
            SizeType l;
            std::memcpy(&l, sizeBuf.data(), sizeof(SizeType));
            l = boost::endian::little_to_native<SizeType>(l);
            auto dataBuf = bufferedReader_.read(is, l);
            if (dataBuf.length() == 0) {
                return std::nullopt;
            }
            if constexpr (bytedata_utils::DirectlySerializableChecker<T>::IsDirectlySerializable()) {
                auto ret = bytedata_utils::RunDeserializer<T>::apply(dataBuf);
                if (!ret) {
                    return std::nullopt;
                }
                return std::tuple<typename Env::TimePointType, T> {
                    *tp
                    , std::move(*ret)
                };
            } else {
                auto ret = bytedata_utils::RunCBORDeserializer<T>::apply(dataBuf, 0);
                if (!ret) {
                    return std::nullopt;
                }
                if (std::get<1>(*ret) != l) {
                    return std::nullopt;
                }
                return std::tuple<typename Env::TimePointType, T> {
                    *tp
                    , std::move(std::get<0>(*ret))
                };
            }
        }
    };

    template <class Duration, class TimeType=int64_t>
    class SystemTimePointWriter {
    public:
        void operator()(void *, std::ostream &os, std::chrono::system_clock::time_point const &tp) {
            TimeType t = boost::endian::native_to_little<TimeType>((TimeType) infra::withtime_utils::sinceEpoch<Duration>(tp));
            os.write(reinterpret_cast<char *>(&t), sizeof(TimeType));
        }
    };
    template <class Duration, class TimeType=int64_t>
    class SystemTimePointReader {
    public:
        static constexpr std::size_t TimeSize = sizeof(TimeType);
        std::optional<std::chrono::system_clock::time_point> operator()(void *, std::string_view const &timeData) {
            TimeType t;
            std::memcpy(&t, timeData.data(), std::min(timeData.length(), sizeof(int64_t)));
            t = boost::endian::little_to_native<TimeType>(t);
            return infra::withtime_utils::epochDurationToTime<Duration>(t);
        }
    };

} } } }

#endif


text:
/*!
 * @file
 * Defines the `check_finite_iterable` utility to ease unit testing of
 * `Iterable`s.
 */

#ifndef BOOST_MPL11_TEST_CHECK_FINITE_ITERABLE_HPP
#define BOOST_MPL11_TEST_CHECK_FINITE_ITERABLE_HPP

#include <boost/mpl11/fwd/comparable.hpp>
#include <boost/mpl11/fwd/iterable.hpp>
#include <boost/mpl11/integer.hpp>

#include "minimal_iterable.hpp"
#include "static_assert.hpp"

namespace check_finite_iter_detail {
    using namespace boost::mpl11;
    using boost::mpl11::size_t;

    template <typename x, typename y,
        typename Expected = typename x::type,
        typename Actual = typename y::type>
    using assert_eq = static_assert_<equal<x, y>>;

    template <typename reference, typename iter,
        typename index = size_t<0>,
        bool = is_empty<reference>::value>
    struct impl;

    template <typename reference, typename iter>
    struct impl<reference, iter, size_t<length<reference>::value>, false>
        : assert_eq<head<reference>, head<iter>>
        , assert_eq<tail<reference>, tail<iter>>
        , assert_eq<is_empty<reference>, is_empty<iter>>

        , assert_eq<last<reference>, last<iter>>
        , assert_eq<length<reference>, length<iter>>
    { };

    template <typename reference, typename iter, typename index>
    struct impl<reference, iter, index, false>
        : assert_eq<at<index, reference>, at<index, iter>>
        , impl<reference, iter, size_t<index::type::value + 1>>
    { };

    template <typename reference, typename iter, typename index>
    struct impl<reference, iter, index, true>
        : static_assert_<is_empty<iter>>
        , assert_eq<size_t<0>, length<iter>>
    { };
} // end namespace check_finite_iter_detail

/*!
 * Generic unit test for finite iterables.
 *
 * To use `check_finite_iterable`, simply instantiate it with the first
 * argument being the tested iterable and `xs...` being the
 * expected contents of the iterable.
 */
template <typename iter, typename ...xs>
using check_finite_iterable =
    check_finite_iter_detail::impl<minimal_iterable<xs...>, iter>;

#endif // !BOOST_MPL11_TEST_CHECK_FINITE_ITERABLE_HPP


text:
// The Reactive C++ Toolbox.
// Copyright (C) 2013-2019 Swirly Cloud Limited
// Copyright (C) 2021 Reactive Markets Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "Exception.hpp"

#include <boost/test/unit_test.hpp>

using namespace toolbox;

BOOST_AUTO_TEST_SUITE(ExceptionSuite)

BOOST_AUTO_TEST_CASE(ExceptionCase)
{
    const auto ec = std::make_error_code(std::errc::invalid_argument);
    const Exception e{ec, "cannot send message"};
    BOOST_TEST(e.what() == "cannot send message");
    BOOST_TEST(e.code() == ec);
    std::stringstream ss;
    ss << put_with_code(e);
    BOOST_TEST(ss.str() == "cannot send message (22)");
}

BOOST_AUTO_TEST_CASE(ExceptionToJsonCase)
{
    const auto ec = std::make_error_code(std::errc::invalid_argument);
    const Exception e{ec, "cannot send message"};

    std::stringstream ss;
    ss << put_as_json(e);

    BOOST_TEST(ss.str() == //
               "{\"code\":22"
               ",\"message\":\"cannot send message\""
               "}");
}

BOOST_AUTO_TEST_SUITE_END()

ext: cpp


text:
/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "xmg_utils.hpp"

#include <boost/format.hpp>
#include <boost/range/iterator_range.hpp>
#include <range/v3/action/remove_if.hpp>

#include <classical/xmg/xmg_cover.hpp>
#include <classical/xmg/xmg_simulate.hpp>

namespace cirkit
{

/******************************************************************************
 * Types                                                                      *
 ******************************************************************************/

/******************************************************************************
 * Private functions                                                          *
 ******************************************************************************/

int compute_depth_rec( const xmg_graph& xmg, xmg_node node, std::vector<int>& depths )
{
  if ( depths[node] >= 0 ) return depths[node];

  if ( xmg.is_input( node ) )
  {
    return depths[node] = 0;
  }
  else
  {
    int depth = 0;
    for ( const auto& c : xmg.children( node ) )
    {
      depth = std::max( compute_depth_rec( xmg, c.node, depths ), depth );
    }
    return depths[node] = ( depth + 1 );
  }
}

/******************************************************************************
 * Public functions                                                           *
 ******************************************************************************/

unsigned compute_depth( const xmg_graph& xmg )
{
  std::vector<int> depths( xmg.size(), -1 );

  int depth = -1;

  for ( const auto& output : xmg.outputs() )
  {
    depth = std::max( compute_depth_rec( xmg, output.first.node, depths ), depth );
  }

  return static_cast<unsigned>( depth );
}

void xmg_print_stats( const xmg_graph& xmg, std::ostream& os )
{
  auto name = xmg.name();
  if ( name.empty() )
  {
    name = "(unnamed)";
  }

  os << boost::format( "[i] %20s: i/o = %7d / %7d  maj = %7d  xor = %7d  lev = %4d" ) % name % xmg.inputs().size() % xmg.outputs().size() % xmg.num_maj() % xmg.num_xor() % compute_depth( xmg );

  if ( xmg.has_cover() )
  {
    os << boost::format( "  luts (k: %d) = %7d" ) % xmg.cover().cut_size() % xmg.cover().lut_count();
  }

  os << std::endl;
}

unsigned compute_pure_maj_count( const xmg_graph& xmg )
{
  auto total = 0u;

  for ( auto v : xmg.nodes() )
  {
    if ( xmg.is_pure_maj( v ) )
    {
      ++total;
    }
  }

  return total;
}

std::vector<unsigned> xmg_compute_levels( const xmg_graph& xmg )
{
  std::vector<unsigned> levels( xmg.size() );
  for ( const auto& n : xmg.topological_nodes() )
  {
    if ( xmg.is_input( n ) )
    {
      levels[n] = 0u;
    }
    else
    {
      auto level = 0u;
      for ( const auto& c : xmg.children( n ) )
      {
        level = std::max( level, levels[c.node] );
      }
      levels[n] = level + 1u;
    }
  }
  return levels;
}

std::vector< std::vector<xmg_node> > xmg_levelize( xmg_graph& xmg )
{
  const auto depth = compute_depth( xmg );
  xmg.compute_levels();

  std::vector< std::vector<xmg_node> > levels( depth+1u );
  for ( const auto& n : xmg.nodes() )
  {
    assert(levels.size() > xmg.level(n));
    levels[xmg.level(n)].push_back( n );
  }

  return levels;
}

std::stack<xmg_node> xmg_output_stack( const xmg_graph& xmg )
{
  std::stack<xmg_node> stack;

  for ( const auto& output : xmg.outputs() )
  {
    stack.push( output.first.node );
  }

  return stack;
}

std::deque<xmg_node> xmg_output_deque( const xmg_graph& xmg )
{
  std::deque<xmg_node> deque;

  for ( const auto& output : xmg.outputs() )
  {
    deque.push_back( output.first.node );
  }

  return deque;
}

tt xmg_simulate_cut( const xmg_graph& xmg, xmg_node root, const std::vector<xmg_node>& leafs )
{
  std::map<xmg_node, tt> inputs;
  auto i = 0u;
  for ( auto child : leafs )
  {
    inputs[child] = tt_nth_var( i++ );
  }

  xmg_tt_simulator tt_sim;
  xmg_partial_node_assignment_simulator<tt> sim( tt_sim, inputs, tt_const0() );

  auto tt = simulate_xmg_node( xmg, root, sim );

  if ( leafs.size() < 6u )
  {
    tt_shrink( tt, leafs.size() );
  }

  return tt;
}

boost::dynamic_bitset<> xmg_output_mask( const xmg_graph& xmg )
{
  boost::dynamic_bitset<> mask( xmg.size() );

  for ( const auto& o : xmg.outputs() )
  {
    mask.set( o.first.node );
  }

  return mask;
}

xmg_edge xmg_get_edge( const xmg_graph& xmg, xmg_node parent, xmg_node child )
{
  for ( const auto& edge : boost::make_iterator_range( boost::out_edges( parent, xmg.graph() ) ) )
  {
    if ( boost::target( edge, xmg.graph() ) == child )
    {
      return edge;
    }
  }

  throw boost::str( boost::format( "no edge between %d and %d" ) % parent % child );
}

void xmg_delete_po_by_node( xmg_graph& xmg, xmg_node node )
{
  ranges::action::remove_if( xmg.outputs(), [node]( const xmg_graph::output_vec_t::value_type& v ) { return v.first.node == node; } );
}

}

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:

max_stars_repo_name: eletesta/cirkit

max_issues_repo_name: eletesta/cirkit

max_forks_repo_name: eletesta/cirkit


text:
// Copyright (C) 2008-2011 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED
#define BOOST_UNORDERED_MAP_FWD_HPP_INCLUDED

#include <boost/config.hpp>
#if defined(BOOST_HAS_PRAGMA_ONCE)
#pragma once
#endif

#include <boost/functional/hash_fwd.hpp>
#include <boost/unordered/detail/fwd.hpp>
#include <functional>
#include <memory>

namespace boost {
  namespace unordered {
    template <class K, class T, class H = boost::hash<K>,
      class P = std::equal_to<K>,
      class A = std::allocator<std::pair<const K, T> > >
    class unordered_map;

    template <class K, class T, class H, class P, class A>
    inline bool operator==(
      unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
    template <class K, class T, class H, class P, class A>
    inline bool operator!=(
      unordered_map<K, T, H, P, A> const&, unordered_map<K, T, H, P, A> const&);
    template <class K, class T, class H, class P, class A>
    inline void swap(
      unordered_map<K, T, H, P, A>& m1, unordered_map<K, T, H, P, A>& m2)
      BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));

    template <class K, class T, class H, class P, class A, class Predicate>
    typename unordered_map<K, T, H, P, A>::size_type erase_if(
      unordered_map<K, T, H, P, A>& c, Predicate pred);

    template <class K, class T, class H = boost::hash<K>,
      class P = std::equal_to<K>,
      class A = std::allocator<std::pair<const K, T> > >
    class unordered_multimap;

    template <class K, class T, class H, class P, class A>
    inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
      unordered_multimap<K, T, H, P, A> const&);
    template <class K, class T, class H, class P, class A>
    inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
      unordered_multimap<K, T, H, P, A> const&);
    template <class K, class T, class H, class P, class A>
    inline void swap(unordered_multimap<K, T, H, P, A>& m1,
      unordered_multimap<K, T, H, P, A>& m2)
      BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.swap(m2)));

    template <class K, class T, class H, class P, class A, class Predicate>
    typename unordered_multimap<K, T, H, P, A>::size_type erase_if(
      unordered_multimap<K, T, H, P, A>& c, Predicate pred);

    template <class N, class K, class T, class A> class node_handle_map;
    template <class N, class K, class T, class A> struct insert_return_type_map;
  }

  using boost::unordered::unordered_map;
  using boost::unordered::unordered_multimap;
  using boost::unordered::swap;
  using boost::unordered::operator==;
  using boost::unordered::operator!=;
}

#endif


text:
#include "./ut_support/UnitTestSupport.hpp"
#include <swizzle/lexer/states/AttributeState.hpp>

#include <swizzle/lexer/Token.hpp>
#include <swizzle/lexer/TokenInfo.hpp>
#include <swizzle/lexer/TokenizerState.hpp>
#include <swizzle/lexer/FileInfo.hpp>

#include <boost/utility/string_view.hpp>
#include <deque>
#include <string>

namespace {
    using namespace swizzle::lexer;

    class CreateTokenCallback
    {
    public:
        CreateTokenCallback(std::deque<TokenInfo>& tokens)
            : tokens_(tokens)
        {
        }

        void operator()(const TokenInfo& info)
        {
            tokens_.push_back(info);
        }

        void operator()(TokenInfo&& info)
        {
            tokens_.emplace_back(info);
        }

    private:
        std::deque<TokenInfo>& tokens_;
    };

    struct AttributeStateFixture
    {
        std::deque<TokenInfo> tokens;
        CreateTokenCallback callback = CreateTokenCallback(tokens);

        FileInfo info = FileInfo("testfile");
        states::AttributeState<CreateTokenCallback> state = states::AttributeState<CreateTokenCallback>(callback);

        std::size_t position = 0;
    };

    TEST_FIXTURE(AttributeStateFixture, verifyConstruction)
    {
    }

    struct WhenNextCharIsAlpha : public AttributeStateFixture
    {
        const std::string s = "a";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsAlpha, verifyConsume)
    {
        // consume a
        const auto tokenState = state.consume(sv, position++, info, token);

        CHECK_EQUAL(TokenizerState::Attribute, tokenState);
        CHECK_EQUAL(TokenType::attribute, token.type());
        CHECK_EQUAL("a", token.to_string());
    }

    struct WhenNextCharIsNumeric : public AttributeStateFixture
    {
        const std::string s = "1";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsNumeric, verifyConsume)
    {
        // consume 1
        const auto tokenState = state.consume(sv, position++, info, token);

        CHECK_EQUAL(TokenizerState::Attribute, tokenState);
        CHECK_EQUAL(TokenType::attribute, token.type());
        CHECK_EQUAL("1", token.to_string());
    }

    struct WhenNextCharIsUnderbar : public AttributeStateFixture
    {
        const std::string s = "_";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsUnderbar, verifyConsume)
    {
        // consume _
        const auto tokenState = state.consume(sv, position++, info, token);

        CHECK_EQUAL(TokenizerState::Attribute, tokenState);
        CHECK_EQUAL(TokenType::attribute, token.type());
        CHECK_EQUAL("_", token.to_string());
    }

    struct WhenNextCharIsDash : public AttributeStateFixture
    {
        const std::string s = "-";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsDash, verifyConsume)
    {
        // consume -
        const auto tokenState = state.consume(sv, position++, info, token);

        CHECK_EQUAL(TokenizerState::Attribute, tokenState);
        CHECK_EQUAL(TokenType::attribute, token.type());
        CHECK_EQUAL("-", token.to_string());
    }

    struct WhenNextCharIsEqual : public AttributeStateFixture
    {
        const std::string s = "a=";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsEqual, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume {
        tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Init, tokenState);

        REQUIRE CHECK_EQUAL(2U, tokens.size());

        CHECK_EQUAL(TokenType::attribute, tokens[0].token().type());
        CHECK_EQUAL("a", tokens[0].token().to_string());

        CHECK_EQUAL(1U, tokens[0].fileInfo().start().line());
        CHECK_EQUAL(1U, tokens[0].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[0].fileInfo().end().line());
        CHECK_EQUAL(2U, tokens[0].fileInfo().end().column());

        CHECK_EQUAL(TokenType::equal, tokens[1].token().type());
        CHECK_EQUAL("=", tokens[1].token().to_string());

        CHECK_EQUAL(1U, tokens[1].fileInfo().start().line());
        CHECK_EQUAL(2U, tokens[1].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[1].fileInfo().end().line());
        CHECK_EQUAL(3U, tokens[1].fileInfo().end().column());
    }

    struct WhenNextCharIsBrace : public AttributeStateFixture
    {
        const std::string s = "a{";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsBrace, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume {
        tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::AttributeBlock, tokenState);

        REQUIRE CHECK_EQUAL(1U, tokens.size());

        CHECK_EQUAL(TokenType::attribute, tokens[0].token().type());
        CHECK_EQUAL("a", tokens[0].token().to_string());

        CHECK_EQUAL(1U, tokens[0].fileInfo().start().line());
        CHECK_EQUAL(1U, tokens[0].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[0].fileInfo().end().line());
        CHECK_EQUAL(2U, tokens[0].fileInfo().end().column());
    }

    struct WhenNextCharIsSpace : public AttributeStateFixture
    {
        const std::string s = "a ";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsSpace, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume space
        tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Init, tokenState);

        REQUIRE CHECK_EQUAL(1U, tokens.size());

        CHECK_EQUAL(TokenType::attribute, tokens[0].token().type());
        CHECK_EQUAL("a", tokens[0].token().to_string());

        CHECK_EQUAL(1U, tokens[0].fileInfo().start().line());
        CHECK_EQUAL(1U, tokens[0].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[0].fileInfo().end().line());
        CHECK_EQUAL(2U, tokens[0].fileInfo().end().column());
    }

    struct WhenNextCharIsTab : public AttributeStateFixture
    {
        const std::string s = "a\t";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsTab, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume tab
        tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Init, tokenState);

        REQUIRE CHECK_EQUAL(1U, tokens.size());

        CHECK_EQUAL(TokenType::attribute, tokens[0].token().type());
        CHECK_EQUAL("a", tokens[0].token().to_string());

        CHECK_EQUAL(1U, tokens[0].fileInfo().start().line());
        CHECK_EQUAL(1U, tokens[0].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[0].fileInfo().end().line());
        CHECK_EQUAL(2U, tokens[0].fileInfo().end().column());
    }

    struct WhenNextCharIsReturn : public AttributeStateFixture
    {
        const std::string s = "a\r";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsReturn, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume \r
        tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Init, tokenState);

        REQUIRE CHECK_EQUAL(1U, tokens.size());

        CHECK_EQUAL(TokenType::attribute, tokens[0].token().type());
        CHECK_EQUAL("a", tokens[0].token().to_string());

        CHECK_EQUAL(1U, tokens[0].fileInfo().start().line());
        CHECK_EQUAL(1U, tokens[0].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[0].fileInfo().end().line());
        CHECK_EQUAL(2U, tokens[0].fileInfo().end().column());
    }

    struct WhenNextCharIsNewLine : public AttributeStateFixture
    {
        const std::string s = "a\n";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsNewLine, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume \n
        tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Init, tokenState);

        REQUIRE CHECK_EQUAL(1U, tokens.size());

        CHECK_EQUAL(TokenType::attribute, tokens[0].token().type());
        CHECK_EQUAL("a", tokens[0].token().to_string());

        CHECK_EQUAL(1U, tokens[0].fileInfo().start().line());
        CHECK_EQUAL(1U, tokens[0].fileInfo().start().column());
        CHECK_EQUAL(1U, tokens[0].fileInfo().end().line());
        CHECK_EQUAL(2U, tokens[0].fileInfo().end().column());
    }

    struct WhenNextCharIsInvalid : public AttributeStateFixture
    {
        const std::string s = "a]";
        const boost::string_view sv = boost::string_view(s);

        Token token = Token(sv, 0, 0, TokenType::attribute);
    };

    TEST_FIXTURE(WhenNextCharIsInvalid, verifyConsume)
    {
        // consume a
        auto tokenState = state.consume(sv, position++, info, token);
        CHECK_EQUAL(TokenizerState::Attribute, tokenState);

        // consume ]
        CHECK_THROW(state.consume(sv, position++, info, token), swizzle::TokenizerError);
    }

}

max_stars_repo_name: SenorAgosto/Swizzle

max_issues_repo_name: SenorAgosto/Swizzle

max_forks_repo_name: SenorAgosto/Swizzle