Ticket #5418: tick_count_timer.cpp

File tick_count_timer.cpp, 6.4 KB (added by Ross MacGregor <gordonrossmacgregor@…>, 12 years ago)

Updated example file: tick_count_timer.cpp

Line 
1//
2// tick_count_timer.cpp
3// ~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2010 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#include <boost/asio.hpp>
12#include <ctime>
13#include <iostream>
14#include <limits>
15#include <cassert>
16
17#if defined(WIN32)
18# include <windows.h>
19#else
20# error This example is for Windows only!
21#endif
22
23#ifdef max // the Windows max macro conflicts with the limits library
24#undef max
25#endif
26
27struct tick_count_traits
28{
29 // The time type. This type has no constructor that takes a DWORD to ensure
30 // that the timer can only be used with relative times.
31 class time_type
32 {
33 public:
34 time_type() : ticks_(0) {}
35 DWORD get_ticks() const {return ticks_;}
36 private:
37 friend struct tick_count_traits;
38 DWORD ticks_;
39 };
40
41 // The duration type.
42 class duration_type
43 {
44 public:
45 duration_type() : ticks_(0) {}
46 duration_type(long ticks) : ticks_(ticks) {}
47 long get_ticks() const {return ticks_;}
48 private:
49 friend struct tick_count_traits;
50 long ticks_;
51 };
52
53 // Get the current time.
54 static time_type now()
55 {
56 time_type result;
57 result.ticks_ = ::GetTickCount();
58 return result;
59 }
60
61 // Add a duration to a time.
62 static time_type add(const time_type& t, const duration_type& d)
63 {
64 time_type result;
65 result.ticks_ = t.ticks_ + d.ticks_;
66 return result;
67 }
68
69 // Subtract one time from another.
70 static duration_type subtract(const time_type& t1, const time_type& t2)
71 {
72 // DWORD tick count values wrap periodically, so we'll use a heuristic that
73 // says that if subtracting t1 from t2 yields a value smaller than 2^31,
74 // then t1 is probably less than t2. This means that we can't handle
75 // durations larger than 2^31, which shouldn't be a problem in practice.
76 static DWORD const diff_limit(static_cast<DWORD>(1 << 31));
77 long duration(0);
78 if (t1.ticks_ < t2.ticks_)
79 {
80 DWORD diff = t2.ticks_ - t1.ticks_;
81 if (diff >= diff_limit)
82 {
83 duration = static_cast<long>(
84 std::numeric_limits<DWORD>::max() - t2.ticks_ + t1.ticks_ + 1);
85 }
86 else
87 {
88 duration = - static_cast<long>(diff);
89 }
90 }
91 else
92 {
93 DWORD diff = t1.ticks_ - t2.ticks_;
94 if (diff >= diff_limit)
95 {
96 duration = - static_cast<long>(
97 std::numeric_limits<DWORD>::max() - t1.ticks_ + t2.ticks_ + 1);
98 }
99 else
100 {
101 duration = static_cast<long>(diff);
102 }
103 }
104 return duration_type(duration);
105 }
106
107 // Test whether one time is less than another.
108 static bool less_than(const time_type& t1, const time_type& t2)
109 {
110 bool is_less = subtract(t2, t1).ticks_ > 0;
111 return is_less;
112 }
113
114 // Convert to POSIX duration type.
115 static boost::posix_time::time_duration to_posix_duration(
116 const duration_type& d)
117 {
118 return boost::posix_time::milliseconds(d.ticks_);
119 }
120};
121
122typedef boost::asio::basic_deadline_timer<
123 DWORD, tick_count_traits> tick_count_timer;
124
125void handle_timeout(const boost::system::error_code&)
126{
127 std::cout << "handle_timeout\n";
128}
129
130int main()
131{
132 typedef tick_count_traits::time_type time_type;
133 typedef tick_count_traits::duration_type duration_type;
134
135 static long const TestDuration = 715827883;
136
137 // tick_count_traits test
138 //
139 time_type t0 = time_type();
140 time_type t1 = tick_count_traits::add(t0, duration_type(TestDuration));
141 time_type t2 = tick_count_traits::add(t1, duration_type(TestDuration));
142 time_type t3 = tick_count_traits::add(t2, duration_type(TestDuration));
143 time_type t4 = tick_count_traits::add(t3, duration_type(TestDuration));
144 time_type t5 = tick_count_traits::add(t4, duration_type(TestDuration));
145 time_type t6 = tick_count_traits::add(t5, duration_type(TestDuration));
146
147 duration_type d1 = tick_count_traits::subtract(t1, t2);
148 duration_type r1 = tick_count_traits::subtract(t2, t1);
149 duration_type d2 = tick_count_traits::subtract(t2, t4);
150 duration_type r2 = tick_count_traits::subtract(t4, t2);
151 duration_type d3 = tick_count_traits::subtract(t4, t5);
152 duration_type r3 = tick_count_traits::subtract(t5, t4);
153 duration_type d4 = tick_count_traits::subtract(t5, t6);
154 duration_type r4 = tick_count_traits::subtract(t6, t5);
155 duration_type d5 = tick_count_traits::subtract(t5, t1);
156 duration_type r5 = tick_count_traits::subtract(t1, t5);
157
158 assert(t0.get_ticks() == 0);
159 assert(t1.get_ticks() == 715827883);
160 assert(t2.get_ticks() == 1431655766);
161 assert(t3.get_ticks() == 2147483649);
162 assert(t4.get_ticks() == 2863311532);
163 assert(t5.get_ticks() == 3579139415);
164 assert(t6.get_ticks() == 2);
165
166 assert(d1.get_ticks() == -715827883);
167 assert(r1.get_ticks() == 715827883);
168 assert(d2.get_ticks() == -1431655766);
169 assert(r2.get_ticks() == 1431655766);
170 assert(d3.get_ticks() == -715827883);
171 assert(r3.get_ticks() == 715827883);
172 assert(d4.get_ticks() == -715827883);
173 assert(r4.get_ticks() == 715827883);
174 assert(d5.get_ticks() == -1431655764); // note due to overrun at t6 this is:
175 assert(r5.get_ticks() == 1431655764); // TestDuration * 2 - 2
176
177 assert(tick_count_traits::less_than(t0, t0) == false);
178 assert(tick_count_traits::less_than(t2, t2) == false);
179 assert(tick_count_traits::less_than(t5, t5) == false);
180
181 assert(tick_count_traits::less_than(t1, t2));
182 assert(tick_count_traits::less_than(t2, t4));
183 assert(tick_count_traits::less_than(t4, t5));
184 assert(tick_count_traits::less_than(t5, t6));
185
186 assert(tick_count_traits::less_than(t2, t1) == false);
187 assert(tick_count_traits::less_than(t4, t2) == false);
188 assert(tick_count_traits::less_than(t5, t4) == false);
189 assert(tick_count_traits::less_than(t6, t5) == false);
190
191 try
192 {
193 boost::asio::io_service io_service;
194
195 tick_count_timer timer(io_service, 5000);
196 std::cout << "Starting synchronous wait\n";
197 timer.wait();
198 std::cout << "Finished synchronous wait\n";
199
200 timer.expires_from_now(5000);
201 std::cout << "Starting asynchronous wait\n";
202 timer.async_wait(handle_timeout);
203 io_service.run();
204 std::cout << "Finished asynchronous wait\n";
205 }
206 catch (std::exception& e)
207 {
208 std::cout << "Exception: " << e.what() << "\n";
209 }
210
211 return 0;
212}