Skip to content

Commit

Permalink
feat(time): add missing methods to ticker/timer
Browse files Browse the repository at this point in the history
  • Loading branch information
conr2d committed Jul 2, 2022
1 parent 10f1eb6 commit 1b23720
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ endif()
include(conan)

set(CONAN_PACKAGES
date/3.0.1
fmt/8.1.1
scope-lite/0.2.0
)
Expand Down Expand Up @@ -66,6 +67,7 @@ if(APPLE)
endif()

find_package(Boost REQUIRED)
find_package(date REQUIRED)
find_package(fmt REQUIRED)
find_package(scope-lite REQUIRED)

Expand Down
2 changes: 2 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ add_executable(channels channels.cpp)
add_executable(channel-directions channel-directions.cpp)
add_executable(select select.cpp)
add_executable(non-blocking-channel-operations non-blocking-channel-operations.cpp)
add_executable(timers timers.cpp)
add_executable(tickers tickers.cpp)
add_executable(waitgroups waitgroups.cpp)
add_executable(mutexes mutexes.cpp)
add_executable(defer defer.cpp)
Expand Down
8 changes: 4 additions & 4 deletions examples/default-selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
using namespace eo;

func<> eo_main() {
auto tick = time::Ticker(std::chrono::milliseconds(100));
auto boom = time::Timer(std::chrono::milliseconds(500));
auto tick = time::new_ticker(std::chrono::milliseconds(100));
auto boom = time::new_timer(std::chrono::milliseconds(500));

auto select = Select{ *tick.ch, *boom.ch, CaseDefault() };
// auto select = Select{ *tick.ch, *boom.ch };
auto select = Select{ *tick->c, *boom->c, CaseDefault() };
// auto select = Select{ *tick.c, *boom.c };

for (;;) {
switch (co_await select.index()) {
Expand Down
59 changes: 59 additions & 0 deletions examples/tickers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// https://gobyexample.com/tickers
//
// package main
//
// import (
// "fmt"
// "time"
// )
//
// func main() {
// ticker := time.NewTicker(500 * time.Millisecond)
// done := make(chan bool)
//
// go func() {
// for {
// select {
// case <-done:
// return
// case t := <-ticker.C:
// fmt.Println("Tick at", t)
// }
// }
// }()
//
// time.Sleep(1600 * time.Millisecond)
// ticker.Stop()
// done <- true
// fmt.Println("Ticker stopped")
// }

#include <eo/fmt.h>
#include <eo/time.h>

using namespace eo;

func<> eo_main() {
auto ticker = time::new_ticker(std::chrono::milliseconds(500));
auto done = make_chan<bool>();

go([&]() -> func<> {
auto select = Select{*done, *ticker->c};
for (;;) {
switch (co_await select.index()) {
case 0:
co_await select.process<0>();
co_return;
case 1:
auto t = co_await select.process<1>();
fmt::println("Tick at {}", t);
break;
}
}
});

co_await time::sleep(std::chrono::milliseconds(1600));
ticker->stop();
co_await *(done << true);
fmt::println("Ticker stopped");
}
49 changes: 49 additions & 0 deletions examples/timers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// package main
//
// import (
// "fmt"
// "time"
// )
//
// func main() {
// timer1 := time.NewTimer(2 * time.Second)
//
// <-timer1.C
// fmt.Println("Timer 1 fired")
//
// timer2 := time.NewTimer(time.Second)
// go func() {
// <-timer2.C
// fmt.Println("Timer 2 fired")
// }()
// stop2 := timer2.Stop()
// if stop2 {
// fmt.Println("Timer 2 stopped")
// }
//
// time.Sleep(2 * time.Second)
// }

#include <eo/fmt.h>
#include <eo/time.h>

using namespace eo;

func<> eo_main() {
auto timer1 = time::new_timer(std::chrono::seconds(2));

co_await **timer1->c;
fmt::println("Timer 1 fired");

auto timer2 = time::new_timer(std::chrono::seconds(1));
go([=]() -> func<> {
co_await **timer2->c;
fmt::println("Timer 2 fired");
});
auto stop2 = timer2->stop();
if (stop2) {
fmt::println("Timer 2 stopped");
}

co_await time::sleep(std::chrono::seconds(2));
}
1 change: 1 addition & 0 deletions src/eo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ add_library(eo STATIC
)
target_include_directories(eo PUBLIC ${PROJECT_SOURCE_DIR}/src ${Boost_INCLUDE_DIR})
target_link_libraries(eo
date::date
fmt::fmt
nonstd::scope-lite
)
Expand Down
13 changes: 13 additions & 0 deletions src/eo/fmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#pragma once
#include <eo/core.h>

#include <date/date.h>
#include <date/tz.h>
#include <fmt/format.h>
#include <map>

Expand Down Expand Up @@ -55,6 +57,17 @@ struct formatter<std::map<K, V>> {
}
};

template<typename Clock>
struct formatter<std::chrono::time_point<Clock>> {
constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
return ctx.end();
}
template<typename FormatContext>
auto format(const std::chrono::time_point<Clock>& p, FormatContext& ctx) {
return format_to(ctx.out(), date::format("%F %T %z %Z", date::make_zoned(date::current_zone(), p)));
}
};

} // namespace fmt

namespace eo {
Expand Down
1 change: 1 addition & 0 deletions src/eo/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ int main(int argc, char** argv) {
std::exception_ptr _eptr{};
boost::asio::co_spawn(runtime::executor, eo_main(), [&](std::exception_ptr eptr) {
_eptr = eptr;
runtime::executor.stop();
});
runtime::executor.join();
if (_eptr) {
Expand Down
35 changes: 26 additions & 9 deletions src/eo/time/ticker.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,50 @@

namespace eo::time {

struct Ticker {
struct Ticker : public std::enable_shared_from_this<Ticker> {
using time_point = std::chrono::system_clock::time_point;

boost::asio::steady_timer timer{runtime::executor};
chan<> ch = make_chan(1);
chan<time_point> c = make_chan<time_point>(1);

Ticker(const std::chrono::steady_clock::duration& d) {
reset(d);
static auto create(const std::chrono::steady_clock::duration& d) -> std::shared_ptr<Ticker> {
auto timer = std::make_shared<Ticker>();
timer->reset(d);
return timer;
}

template<typename Executor>
Ticker(const std::chrono::steady_clock::duration& d, Executor& executor): timer(executor) {
reset(d);
static auto create_with_executor(const std::chrono::steady_clock::duration& d, Executor& executor) -> std::shared_ptr<Ticker> {
auto timer = std::make_shared<Ticker>(executor);
timer->reset(d);
return timer;
}

Ticker() = default;

template<typename Executor>
Ticker(Executor& executor): timer(executor) {}

~Ticker() {
timer.cancel();
}

void reset(const std::chrono::steady_clock::duration& d) {
timer.cancel();
timer.expires_after(d);
timer.async_wait([this, d{d}](boost::system::error_code ec) {
timer.async_wait([=, self{shared_from_this()}](boost::system::error_code ec) {
if (ec)
return;
ch.try_send(boost::system::error_code{}, std::monostate{});
reset(d);
self->c.try_send(boost::system::error_code{}, std::chrono::system_clock::now());
self->reset(d);
});
}

void stop() {
timer.cancel();
}
};

const auto new_ticker = Ticker::create;

} // namespace eo::time
40 changes: 32 additions & 8 deletions src/eo/time/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,56 @@

namespace eo::time {

struct Timer {
struct Timer : public std::enable_shared_from_this<Timer> {
using time_point = std::chrono::system_clock::time_point;

boost::asio::steady_timer timer{runtime::executor};
chan<> ch = make_chan(1);
chan<time_point> c = make_chan<time_point>(1);
bool expired;

Timer(const std::chrono::steady_clock::duration& d) {
reset(d);
static auto create(const std::chrono::steady_clock::duration& d) -> std::shared_ptr<Timer> {
auto timer = std::make_shared<Timer>();
timer->reset(d);
return timer;
}

template<typename Executor>
Timer(const std::chrono::steady_clock::duration& d, Executor& executor): timer(executor) {
reset(d);
static auto create_with_executor(const std::chrono::steady_clock::duration& d, Executor& executor) -> std::shared_ptr<Timer> {
auto timer = std::make_shared<Timer>(executor);
timer->reset(d);
return timer;
}

Timer() = default;

template<typename Executor>
Timer(Executor& executor): timer(executor) {}

~Timer() {
timer.cancel();
}

void reset(const std::chrono::steady_clock::duration& d) {
timer.cancel();
timer.expires_after(d);
timer.async_wait([this, d{d}](boost::system::error_code ec) {
expired = false;
timer.async_wait([=, self{shared_from_this()}](boost::system::error_code ec) {
self->expired = true;
if (ec)
return;
ch.try_send(boost::system::error_code{}, std::monostate{});
self->c.try_send(boost::system::error_code{}, std::chrono::system_clock::now());
});
}

auto stop() -> bool {
if (expired) {
return false;
}
timer.cancel();
return !std::exchange(expired, true);
}
};

const auto new_timer = Timer::create;

} // namespace eo::time

0 comments on commit 1b23720

Please sign in to comment.