Line data Source code
1 : // Copyright (c) 2021-2022 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : #pragma once
20 :
21 : // libexcept
22 : //
23 : #include <libexcept/exception.h>
24 :
25 :
26 : // C++
27 : //
28 : #include <cmath>
29 : #include <cstdint>
30 : #include <iomanip>
31 : #include <iostream>
32 : #include <sstream>
33 :
34 :
35 : // C
36 : //
37 : #include <stdlib.h>
38 : #include <sys/time.h>
39 : #include <time.h>
40 :
41 :
42 :
43 :
44 : namespace snapdev
45 : {
46 :
47 : DECLARE_MAIN_EXCEPTION(timespec_ex_exception);
48 :
49 : DECLARE_EXCEPTION(timespec_ex_exception, overflow);
50 :
51 :
52 : class timespec_ex
53 : : public timespec
54 : {
55 : public:
56 : /** \brief Initialize a timespec_ex to zero.
57 : *
58 : * This constructor is used to initialize a new timespec_ex to the
59 : * default value, which is 0.
60 : */
61 38 : timespec_ex()
62 38 : {
63 38 : set(0L);
64 38 : }
65 :
66 :
67 : /** \brief Initialize a timespec_ex from another.
68 : *
69 : * This constructors allows you to directly copy a timespec_ex
70 : * in another new timespec_ex object.
71 : *
72 : * \param[in] t The timespec_ex to directly copy.
73 : */
74 62 : timespec_ex(timespec_ex const & t)
75 62 : {
76 62 : set(t);
77 62 : }
78 :
79 :
80 : /** \brief Initialize a timespec_ex from a timespec structure.
81 : *
82 : * This constructors allows you to directly set a timespec_ex
83 : * to the specified timespec values.
84 : *
85 : * \param[in] t The timespec to directly copy.
86 : */
87 59 : timespec_ex(timespec const & t)
88 59 : {
89 59 : set(t);
90 59 : }
91 :
92 :
93 : /** \brief Initialize a timespec_ex from seconds and nanoseconds.
94 : *
95 : * This constructors allows you to directly initialize a timespec_ex
96 : * from seconds and nanoseconds.
97 : *
98 : * To create a valid timespec_ex object, you must pass a number
99 : * between 0 and 999'999'999 for the \p nsec parameter.
100 : *
101 : * \param[in] sec The number of seconds.
102 : * \param[in] nsec The number of nano-seconds.
103 : */
104 6 : timespec_ex(time_t sec, long nsec)
105 6 : {
106 6 : set(sec, nsec);
107 6 : }
108 :
109 :
110 : /** \brief Initialize a timespec_ex from an int64_t in nanoseconds.
111 : *
112 : * This constructors allows you to directly set a timespec_ex
113 : * to the specified \p nsec value.
114 : *
115 : * \param[in] nsec The nano-seconds to copy to timespec_ex.
116 : */
117 28 : timespec_ex(std::int64_t nsec)
118 28 : {
119 28 : set(nsec);
120 28 : }
121 :
122 :
123 : /** \brief Initialize a timespec_ex from an double in seconds.
124 : *
125 : * This constructors allows you to directly set a timespec_ex
126 : * to the specified \p sec value.
127 : *
128 : * \param[in] sec The seconds to copy to timespec_ex.
129 : */
130 14 : timespec_ex(double sec)
131 14 : {
132 14 : set(sec);
133 14 : }
134 :
135 :
136 : /** \brief Set the timespec_ex to the specified timespec_ex.
137 : *
138 : * This function copies the specified timespec_ex (\p t) to this
139 : * timespec_ex object.
140 : *
141 : * \param[in] t The timespec to copy in this timespec_ex.
142 : *
143 : * \return A reference to this object.
144 : */
145 47 : timespec_ex & operator = (timespec_ex t)
146 : {
147 47 : tv_sec = t.tv_sec;
148 47 : tv_nsec = t.tv_nsec;
149 47 : return *this;
150 : }
151 :
152 :
153 : /** \brief Set the timespec_ex to the specified timespec.
154 : *
155 : * This function copies the specified timespec to this timespec_ex
156 : * object.
157 : *
158 : * \param[in] t The timespec to copy in this timespec_ex.
159 : *
160 : * \return A reference to this object.
161 : */
162 1 : timespec_ex & operator = (timespec const & t)
163 : {
164 1 : tv_sec = t.tv_sec;
165 1 : tv_nsec = t.tv_nsec;
166 1 : return *this;
167 : }
168 :
169 :
170 : /** \brief Set the timespec_ex to the number of nanoseconds.
171 : *
172 : * This function saves the number of nanoseconds in \p nsec as a
173 : * tv_sec and tv_nsec representation.
174 : *
175 : * \param[in] nsec The nano-seconds to save in this timespec_ex.
176 : *
177 : * \return A reference to this object.
178 : */
179 1 : timespec_ex & operator = (std::int64_t nsec)
180 : {
181 1 : set(nsec);
182 1 : return *this;
183 : }
184 :
185 :
186 : /** \brief Set this timespec_ex to the number of seconds in \p sec.
187 : *
188 : * This function transforms the specified double \p sec in a timespec_ex.
189 : *
190 : * \note
191 : * At this time, the number of nanoseconds is floored.
192 : *
193 : * \param[in] sec The number of seconds defined in a double.
194 : *
195 : * \return A reference to this object.
196 : */
197 3 : timespec_ex & operator = (double sec)
198 : {
199 3 : set(sec);
200 3 : return *this;
201 : }
202 :
203 :
204 : /** \brief Set the timespec_ex to the number of nanoseconds.
205 : *
206 : * This function saves the number of nanoseconds in \p nsec as a
207 : * tv_sec and tv_nsec representation.
208 : *
209 : * \param[in] t The nano-seconds to save in this timespec_ex.
210 : *
211 : * \return A reference to this object.
212 : */
213 62 : void set(timespec_ex const & t)
214 : {
215 62 : tv_sec = t.tv_sec;
216 62 : tv_nsec = t.tv_nsec;
217 62 : }
218 :
219 :
220 : /** \brief Set the timespec_ex to the specified timespec.
221 : *
222 : * This function copies the timespec in \p t in this timespec_ex object.
223 : *
224 : * \param[in] t The timespec to save in this timespec_ex.
225 : *
226 : * \return A reference to this object.
227 : */
228 59 : void set(timespec const & t)
229 : {
230 59 : tv_sec = t.tv_sec;
231 59 : tv_nsec = t.tv_nsec;
232 59 : }
233 :
234 :
235 : /** \brief Set the timespec_ex to the specified values.
236 : *
237 : * This function allows you to set the timespec_ex to the specified
238 : * number of seconds (\p sec) and nano-seconds (\p nsec).
239 : *
240 : * \param[in] sec The new number of seconds.
241 : * \param[in] nsec The new number of nano-seconds.
242 : */
243 6 : void set(time_t sec, long nsec)
244 : {
245 6 : tv_sec = sec;
246 6 : tv_nsec = nsec;
247 6 : }
248 :
249 :
250 : /** \brief Set the timespec_ex to the number of nanoseconds.
251 : *
252 : * This function saves the number of nanoseconds in \p nsec as a
253 : * tv_sec and tv_nsec representation.
254 : *
255 : * \param[in] nsec The nano-seconds to save in this timespec_ex.
256 : *
257 : * \return A reference to this object.
258 : */
259 67 : void set(std::int64_t nsec)
260 : {
261 67 : bool const neg(nsec < 0);
262 67 : if(neg)
263 : {
264 8 : nsec = -nsec;
265 : }
266 67 : tv_sec = static_cast<time_t>(nsec / 1'000'000'000LL);
267 67 : tv_nsec = static_cast<long>(nsec % 1'000'000'000LL);
268 67 : if(neg)
269 : {
270 8 : *this = -*this;
271 : }
272 67 : }
273 :
274 :
275 : /** \brief Set this timespec_ex to the number of seconds in \p sec.
276 : *
277 : * This function transforms the specified double \p sec in a timespec_ex.
278 : *
279 : * \note
280 : * At this time, the number of nanoseconds is floored.
281 : *
282 : * \param[in] sec The number of seconds defined in a double.
283 : *
284 : * \return A reference to this object.
285 : */
286 17 : void set(double sec)
287 : {
288 17 : bool const neg(sec < 0.0);
289 17 : if(neg)
290 : {
291 1 : sec = -sec;
292 : }
293 17 : tv_sec = static_cast<time_t>(floor(sec));
294 17 : tv_nsec = static_cast<long>((sec - floor(sec)) * 1.0e9);
295 17 : if(neg)
296 : {
297 1 : *this = -*this;
298 : }
299 17 : }
300 :
301 : /** \brief Get system time.
302 : *
303 : * This function reads the system time and saves it into this
304 : * timespec_ex object.
305 : *
306 : * \todo
307 : * Look into whether we want to return an error if clock_gettime()
308 : * fails.
309 : *
310 : * \param[in] clk_id The type of clock you want to query.
311 : *
312 : * \return A timespec_ex representing the specified \p clk_id.
313 : */
314 1 : static timespec_ex gettime(clockid_t clk_id = CLOCK_REALTIME)
315 : {
316 1 : timespec_ex result;
317 1 : clock_gettime(clk_id, &result);
318 1 : return result;
319 : }
320 :
321 :
322 : /** \brief Extract the timespec_ex as an int64_t value.
323 : *
324 : * This function transforms a timespec_ex structure in an int64_t
325 : * in nanoseconds.
326 : *
327 : * \return This timespec_ex converted to nanoseconds.
328 : */
329 1 : std::int64_t to_nsec() const
330 : {
331 1 : return tv_nsec
332 1 : + tv_sec * 1'000'000'000LL;
333 : }
334 :
335 :
336 : /** \brief Extract the timespec_ex as a double value.
337 : *
338 : * This function transforms a timespec_ex structure into a double
339 : * in seconds. The nanoseconds are added as one billionth of a
340 : * second.
341 : *
342 : * \return The timespec_ex converted the seconds.
343 : */
344 6 : double to_sec() const
345 : {
346 6 : return static_cast<double>(tv_sec)
347 6 : + static_cast<double>(tv_nsec) / 1.0e9;
348 : }
349 :
350 :
351 : /** \brief Format the date to the specified format.
352 : *
353 : * This function transforms the time in a string and returns that string.
354 : * The function uses the strftime(). See that manual page to define
355 : * the format properly.
356 : *
357 : * Unless you use the `%N` extension, the output will not include the
358 : * precision available in the timespec (i.e. without the %N, the output
359 : * is to the second, the timespec has nanoseconds available).
360 : *
361 : * \param[in] format The format used to transform the date and time in
362 : * a string.
363 : * \param[in] local Whether to generate a local time or use UTC.
364 : *
365 : * \return The formatted date and time.
366 : */
367 : std::string to_string(std::string const & format = std::string(), bool local = false) const
368 : {
369 : struct tm date_and_time = {};
370 : struct tm * ptr(nullptr);
371 : if(local)
372 : {
373 : ptr = localtime_r(&tv_sec, &date_and_time);
374 : }
375 : else
376 : {
377 : ptr = gmtime_r(&tv_sec, &date_and_time);
378 : }
379 : if(ptr == nullptr)
380 : {
381 : throw overflow("the specified number of seconds could not be transformed in a 'struct tm'.");
382 : }
383 : std::string f(format);
384 : if(f.empty())
385 : {
386 : // TODO: actually retrieve the locale() format and
387 : // search for "%T" or "%S" and insert ".%N"
388 : // right after either
389 : //
390 : f = "%c.%N";
391 : }
392 : std::string::size_type pos(f.find("%N"));
393 : if(pos != std::string::npos)
394 : {
395 : std::string n(std::to_string(tv_nsec));
396 : if(n.length() > 9)
397 : {
398 : throw overflow("tv_nsec is 1 billion or more, which is invalid.");
399 : }
400 : std::string const indent(9 - n.length(), '0');
401 : n = indent + n;
402 : f = f.substr(0, pos) + n + f.substr(pos + 2);
403 : }
404 : char buf[256];
405 : size_t const sz(strftime(buf, sizeof(buf), f.c_str(), &date_and_time));
406 : if(sz == 0)
407 : {
408 : // this happens with just a "%p" and "wrong locale"
409 : // or when the buffer is too small, which should not
410 : // be the case unless you add much more than the format
411 : // in that string
412 : //
413 : throw overflow(
414 : "the specified strftime() format \""
415 : + format
416 : + "\" failed.");
417 : }
418 :
419 : return std::string(buf, sz);
420 : }
421 :
422 :
423 : /** \brief Validate this timespec_ex structure.
424 : *
425 : * This function returns true if this timespec_ex structure is considered
426 : * valid.
427 : *
428 : * At this time, the validation consists of verifying that the
429 : * nanoseconds is a number between 0 and 1 billion (maximum excluded).
430 : *
431 : * \note
432 : * Negative timespec_ex are represented by a negative tv_sec. The
433 : * tv_nsec can never be negative after a valid operation.
434 : *
435 : * \return true if the timespec_ex is considered valid.
436 : */
437 7 : bool valid() const
438 : {
439 7 : return tv_nsec < 1'000'000'000LL;
440 : }
441 :
442 :
443 : /** \brief Check whether this timespec_ex is negative.
444 : *
445 : * This function checks whether the number represents a negative
446 : * timespec_ex. This is true if the number of seconds is negative.
447 : *
448 : * \note
449 : * The first negative timespec_ex is { -1, 999,999,999 }.
450 : *
451 : * \return true if the timespec_ex is considered negative.
452 : */
453 72 : bool negative() const
454 : {
455 72 : return tv_sec < 0LL;
456 : }
457 :
458 :
459 : /** \brief Add two timespec_ex together.
460 : *
461 : * This function adds \p rhs to this timespec_ex value and returns a
462 : * new timespec_ex with the result. This timespec_ex is not modified.
463 : *
464 : * \param[in] rhs The right handside to add to this number.
465 : *
466 : * \return A new timespec_ex representing the sum of 'this' and rhs.
467 : */
468 33 : timespec_ex add(timespec_ex const & rhs) const
469 : {
470 33 : bool const lneg(negative());
471 33 : bool const rneg(rhs.negative());
472 :
473 33 : timespec_ex lp(lneg ? -*this : *this);
474 33 : timespec_ex rp(rneg ? -rhs : rhs);
475 :
476 33 : timespec_ex result;
477 :
478 33 : switch((lneg ? 1 : 0) + (rneg ? 2 : 0))
479 : {
480 16 : case 0: // positive + positive
481 : case 3: // negative + negative
482 16 : result.tv_sec = lp.tv_sec + rp.tv_sec;
483 16 : result.tv_nsec = lp.tv_nsec + rp.tv_nsec;
484 16 : break;
485 :
486 3 : case 1: // negative + positive
487 3 : result.tv_sec = rp.tv_sec - lp.tv_sec;
488 3 : result.tv_nsec = rp.tv_nsec - lp.tv_nsec;
489 3 : break;
490 :
491 14 : case 2: // positive + negative
492 14 : result.tv_sec = lp.tv_sec - rp.tv_sec;
493 14 : result.tv_nsec = lp.tv_nsec - rp.tv_nsec;
494 14 : break;
495 :
496 : }
497 :
498 33 : if(result.tv_nsec < 0)
499 : {
500 4 : --result.tv_sec;
501 4 : result.tv_nsec += 1'000'000'000L;
502 : }
503 29 : else if(result.tv_nsec >= 1'000'000'000)
504 : {
505 5 : ++result.tv_sec;
506 5 : result.tv_nsec -= 1'000'000'000;
507 : }
508 :
509 33 : if(lneg && rneg)
510 : {
511 2 : result = -result;
512 : }
513 :
514 33 : return result;
515 : }
516 :
517 :
518 : /** \brief Compare two timespec_ex together.
519 : *
520 : * This function compares two timespecs and determine whether they
521 : * are equal (0), 'this' is smaller (-1) or \p rhs is smaller (1).
522 : *
523 : * \param[in] rhs The right handside to compare.
524 : *
525 : * \return -1, 0, or 1 depending on the order between \p lhs and \p rhs.
526 : */
527 97 : int compare(timespec_ex const & rhs) const
528 : {
529 97 : if(tv_sec == rhs.tv_sec)
530 : {
531 85 : return tv_nsec == rhs.tv_nsec
532 112 : ? 0
533 112 : : (tv_nsec < rhs.tv_nsec ? -1 : 1);
534 : }
535 :
536 12 : return tv_sec < rhs.tv_sec ? -1 : 1;
537 : }
538 :
539 :
540 : /** \brief Check whether the timespec_ex is zero.
541 : *
542 : * This function returns true if the timespec_ex represents zero
543 : * (i.e. zero seconds and zero nano-seconds).
544 : *
545 : * \return true if the timespec_ex is zero, false if not zero.
546 : */
547 11 : bool operator ! ()
548 : {
549 11 : return tv_sec == 0 && tv_nsec == 0;
550 : }
551 :
552 :
553 : /** \brief Add the right handside to this timespec_ex.
554 : *
555 : * This operator adds the right handside to this object.
556 : *
557 : * \param[in] rhs Another timespec_ex to add to this one.
558 : *
559 : * \return A reference to this timespec_ex object.
560 : */
561 19 : timespec_ex & operator += (timespec_ex const & rhs)
562 : {
563 19 : *this = add(rhs);
564 19 : return *this;
565 : }
566 :
567 :
568 : /** \brief Add 1 nanosecond to this timespec_ex object.
569 : *
570 : * This function adds exactly one nanonsecond to this timespec_ex
571 : * object.
572 : *
573 : * \return A reference to this timespec_ex object.
574 : */
575 3 : timespec_ex & operator ++ ()
576 : {
577 3 : *this += 1L;
578 3 : return *this;
579 : }
580 :
581 :
582 : /** \brief Add 1 nanosecond to this timespec_ex object.
583 : *
584 : * This function adds exactly one nanonsecond to this timespec_ex
585 : * object and returns the original value.
586 : *
587 : * \return A copy of this timespec_ex object before the add() occurs.
588 : */
589 1 : timespec_ex operator ++ (int)
590 : {
591 1 : timespec_ex result(*this);
592 1 : *this += 1L;
593 1 : return result;
594 : }
595 :
596 :
597 : /** \brief Add two timespec_ex objects and return the result.
598 : *
599 : * This function computes the addition of this timespec_ex object
600 : * and the \p t timespec_ex and returns the result. The inputs
601 : * are not modified.
602 : *
603 : * \param[in] t The right handside to add to this timespex_ex object.
604 : *
605 : * \return The sum of the inputs in a new timespec_ex object.
606 : */
607 7 : timespec_ex operator + (timespec_ex const & t) const
608 : {
609 7 : timespec_ex result(*this);
610 7 : result += t;
611 7 : return result;
612 : }
613 :
614 :
615 : /** \brief Subtract the right handside from this timespec_ex.
616 : *
617 : * This operator subtracts the right handside from this object.
618 : *
619 : * \param[in] rhs Another timespec_ex to subtract from this one.
620 : *
621 : * \return A reference to this timespec_ex object.
622 : */
623 14 : timespec_ex & operator -= (timespec_ex const & rhs)
624 : {
625 14 : *this = add(-rhs);
626 14 : return *this;
627 : }
628 :
629 :
630 : /** \brief Subtract 1 nanosecond from timespec_ex object.
631 : *
632 : * This function subtracts exactly one nanonsecond from this
633 : * timespec_ex object.
634 : *
635 : * \return A reference to this timespec_ex object.
636 : */
637 3 : timespec_ex & operator -- ()
638 : {
639 3 : *this -= 1L;
640 3 : return *this;
641 : }
642 :
643 :
644 : /** \brief Subtract 1 nanosecond from timespec_ex object.
645 : *
646 : * This function subtracts exactly one nanonsecond from this
647 : * timespec_ex object and returns the original value.
648 : *
649 : * \return A copy of this timespec_ex object before the subtract occurs.
650 : */
651 1 : timespec_ex operator -- (int)
652 : {
653 1 : timespec_ex result(*this);
654 1 : *this -= 1L;
655 1 : return result;
656 : }
657 :
658 :
659 : /** \brief Compute the additive opposite of the right handside timespec_ex.
660 : *
661 : * This function computers the opposite of the right handside timespec_ex
662 : * and returns a copy with the result.
663 : *
664 : * This is equivalent to computing `0 - t`.
665 : *
666 : * \param[in] t The right handside time to negate.
667 : *
668 : * \return A timespec_ex representing the additive opposite of the input.
669 : */
670 49 : timespec_ex operator - () const
671 : {
672 49 : timespec_ex result(timespec{ -tv_sec, -tv_nsec });
673 49 : if(result.tv_nsec < 0)
674 : {
675 48 : --result.tv_sec;
676 48 : result.tv_nsec += 1'000'000'000L;
677 : }
678 49 : return result;
679 : }
680 :
681 :
682 : /** \brief Subtract \p t from this timespec_ex object.
683 : *
684 : * This function computes the difference of this timespec_ex object
685 : * and the \p t timespec_ex object and returns the result. The inputs
686 : * are not modified.
687 : *
688 : * \param[in] rhs The right handside to subtract from this timespex_ex
689 : * object.
690 : *
691 : * \return The different of the inputs in a new timespec_ex object.
692 : */
693 6 : timespec_ex operator - (timespec_ex const & rhs) const
694 : {
695 6 : timespec_ex result(*this);
696 6 : result -= rhs;
697 6 : return result;
698 : }
699 :
700 :
701 : /** \brief Compare whether the two timespec_ex are equal.
702 : *
703 : * \param[in] t The time to compare against.
704 : *
705 : * \return true if both timespec_ex objects are equal.
706 : */
707 23 : bool operator == (timespec_ex const & t) const
708 : {
709 23 : return compare(t) == 0;
710 : }
711 :
712 :
713 : /** \brief Compare whether the two timespec_ex are not equal.
714 : *
715 : * \param[in] t The time to compare against.
716 : *
717 : * \return true if both timespec_ex objects are not equal.
718 : */
719 15 : bool operator != (timespec_ex const & t) const
720 : {
721 15 : return compare(t) != 0;
722 : }
723 :
724 :
725 : /** \brief Compare whether the left handside is smaller.
726 : *
727 : * \param[in] t The time to compare against.
728 : *
729 : * \return true if the left handside timespec_ex object is smaller.
730 : */
731 15 : bool operator < (timespec_ex const & t) const
732 : {
733 15 : return compare(t) == -1;
734 : }
735 :
736 :
737 : /** \brief Compare whether the left handside is smaller or equal.
738 : *
739 : * \param[in] t The time to compare against.
740 : *
741 : * \return true if the left handside timespec_ex object is smaller
742 : * or equal.
743 : */
744 15 : bool operator <= (timespec_ex const & t) const
745 : {
746 15 : return compare(t) <= 0;
747 : }
748 :
749 :
750 : /** \brief Compare whether the left handside is larger.
751 : *
752 : * \param[in] t The time to compare against.
753 : *
754 : * \return true if the left handside timespec_ex object is larger.
755 : */
756 14 : bool operator > (timespec_ex const & t) const
757 : {
758 14 : return compare(t) == 1;
759 : }
760 :
761 :
762 : /** \brief Compare whether the left handside is larger or equal.
763 : *
764 : * \param[in] t The time to compare against.
765 : *
766 : * \return true if the left handside timespec_ex object is larger
767 : * or equal.
768 : */
769 15 : bool operator >= (timespec_ex const & t) const
770 : {
771 15 : return compare(t) >= 0;
772 : }
773 : };
774 :
775 :
776 :
777 :
778 :
779 :
780 :
781 : /** \brief Output a timespec to a basic_ostream.
782 : *
783 : * This function allows one to print out a timespec. By default the function
784 : * prints the timespec as a floating point.
785 : *
786 : * \todo
787 : * Look into the possibility to write the data as Y/M/D H:M:S.nanosecs
788 : *
789 : * \param[in] out The output stream where the timespec gets written.
790 : * \param[in] t The actual timespec that is to be printed.
791 : *
792 : * \return A reference to the basic_ostream object.
793 : */
794 : template<typename CharT, typename Traits>
795 3 : std::basic_ostream<CharT, Traits> & operator << (std::basic_ostream<CharT, Traits> & out, timespec const & t)
796 : {
797 : // write to a string buffer first
798 : //
799 6 : std::basic_ostringstream<CharT, Traits, std::allocator<CharT> > s;
800 :
801 : // setup the string output like the out stream
802 : //
803 3 : s.flags(out.flags());
804 3 : s.imbue(out.getloc());
805 3 : s.precision(out.precision());
806 3 : s << t.tv_sec << "." << std::setw(9) << std::setfill('0') << t.tv_nsec;
807 :
808 : // buffer is ready, display in output in one go
809 : //
810 6 : return out << s.str();
811 : }
812 :
813 :
814 : } // namespace snapdev
815 : // vim: ts=4 sw=4 et
|