Skip to content

Latest commit

 

History

History
341 lines (282 loc) · 6.96 KB

297.md

File metadata and controls

341 lines (282 loc) · 6.96 KB
Info

Example

struct task {
  struct promise_type {
    task get_return_object() { return {}; }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    template<class T> void return_value(T) {}
    void unhandled_exception() {}
  };
};

template<class T>
class awaiter {
 public:
  auto operator co_await() {
    struct {
      awaiter& aw;

      auto await_ready() const noexcept -> bool { return aw.value; }
      auto await_suspend(std::coroutine_handle<> coroutine) noexcept {
        aw.coroutine = coroutine;
        return true;
      }

      auto await_resume() const noexcept {
        struct reset {
          T& value;
          ~reset() { value = {}; }
        } _{aw.value};
        return aw.value;
      }
    } awaiter{*this};

    return awaiter;
  }

  void process(const T& value) {
    this->value = value;
    coroutine.resume();
  }

 private:
  T value{};
  std::coroutine_handle<> coroutine{};
};

int main() {
    auto input = awaiter<int>{};
    auto sum = 0;

    const auto await_sum = [](auto& input, auto& sum) -> task {
      for (;;) {
        sum += co_await input;
      }
    };

    [[maybe_unused]] auto _ = await_sum(input, sum);
    input.process(1);
    assert(1 == sum);

    input.process(42);
    assert(43 == sum);

    input.process(-10);
    assert(33 == sum);
}

https://godbolt.org/z/fo4j1Mn8Y

Puzzle

class parser {
 public:
  explicit parser(std::stringstream& out) : out{out} { }

  void parse(std::string_view in) {
    for (const auto value : in) {
       input.process(value);
    }
  }

 private:
  task parse_impl() {
    // TODO
  }

  awaiter<char> input{};
  task start{parse_impl()};
  std::stringstream& out;
};

int main() {
  {
    std::stringstream out{};
    parser p{out};
    p.parse("0");
    assert("0" == out.str());
  }

  {
    std::stringstream out{};
    parser p{out};
    p.parse("01");
    assert("00" == out.str());
  }

  {
    std::stringstream out{};
    parser p{out};
    p.parse("0110");
    assert("0001" == out.str());
  }

  {
    std::stringstream out{};
    parser p{out};
    p.parse("0001");
    assert("0000" == out.str());
  }

  {
    std::stringstream out{};
    parser p{out};
    p.parse("000110");
    assert("000001" == out.str());
  }

  {
    std::stringstream out{};
    parser p{out};
    p.parse("0110100010010001101001000111110010011001");
    assert("0001000000000000010000000000001000000100" == out.str());
  }
}

https://godbolt.org/z/6cxdqEno1

Solutions

struct task {
  struct promise_type {
    task get_return_object() { return {}; }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    template<class T> void return_value(T) { }
    void unhandled_exception() {}
  };
};

template<class T>
class awaiter {
 public:
  auto operator co_await() {
    struct {
      awaiter& aw;

      auto await_ready() const noexcept -> bool { return static_cast<bool>(aw.value); }
      auto await_suspend(std::coroutine_handle<> coroutine) noexcept {
        aw.coroutine = coroutine;
        return true;
      }

      auto await_resume() const noexcept {
        struct reset {
         std::optional<T>& value;
          ~reset() { value = {}; }
        } _{aw.value};
        return *aw.value - '0';
      }
    } awaiter{*this};

    return awaiter;
  }

  void process(const T& value) {
    this->value = value;
    coroutine.resume();
  }

 private:
  std::optional<T> value{};
  std::coroutine_handle<> coroutine{};
};

class parser {
 public:
  explicit parser(std::stringstream& out) : out{out} { }

  void parse(std::string_view in) {
    for (const auto value : in) {
      input.process(value);
    }
  }

 private:
  task parse_impl() {
    enum state { A, B, C } state;
    for (;;) {
      const auto value = co_await input;
      const auto in = value != 0;
      switch (state) {
          case A:
              out << '0';
              state = in ? B : A;
              break;
          case B:
              out << '0';
              state = in ? C : A;
              break;
          case C:
              out << (in ? '0' : '1');
              state = in ? C : A;
              break;
      };
    }
  }

  awaiter<char> input{};
  task start{parse_impl()};
  std::stringstream& out;
};

https://godbolt.org/z/Yxc58vrWW

struct task {
  struct promise_type {
    task get_return_object() { return {}; }
    std::suspend_never initial_suspend() { return {}; }
    std::suspend_never final_suspend() noexcept { return {}; }
    template <class T>
    void return_value(T) {}
    void unhandled_exception() {}
  };
};

template <class T>
class awaiter {
 public:
  auto operator co_await() {
    struct {
      awaiter& aw;

      auto await_ready() const noexcept -> bool {
        return static_cast<bool>(aw.value);
      }
      auto await_suspend(std::coroutine_handle<> coroutine) noexcept {
        aw.coroutine = coroutine;
        return true;
      }

      auto await_resume() const noexcept {
        struct reset {
          std::optional<T>& value;
          ~reset() { value = {}; }
        } _{aw.value};
        return *aw.value - '0';
      }
    } awaiter{*this};

    return awaiter;
  }

  void process(const T& value) {
    this->value = value;
    coroutine.resume();
  }

 private:
  std::optional<T> value{};
  std::coroutine_handle<> coroutine{};
};

class parser {
 public:
  explicit parser(std::stringstream& out) : out{out} {}

  void parse(std::string_view in) {
    for (const auto value : in) {
      input.process(value);
    }
  }

 private:
  task parse_impl() {
    struct data {
      int value;
    };

    using namespace boost::sml;
    front::sm sm = [this] {
      constexpr auto is = [](auto value) {
        return [=](auto e) { return e.value == value; };
      };
      const auto print = [this](auto value) {
        return [=, this] { out << value; };
      };

      return make_transition_table(
          // clang-format off
         *"0"_s + event<data> [is(1)] / print(0) = "1"_s,
          "0"_s + event<data>         / print(0),
          "1"_s + event<data> [is(1)] / print(0) = "2"_s,
          "1"_s + event<data>         / print(0) = "0"_s,
          "2"_s + event<data> [is(0)] / print(1) = "0"_s,
          "2"_s + event<data>         / print(0)
          // clang-format on
      );
    };

    while (true) {
      sm.process_event(data{.value = co_await input});
    }
  }

  awaiter<char> input{};
  task start{parse_impl()};
  std::stringstream& out;
};

https://godbolt.org/z/1fo5q4M4K