rangeless::fn
calendar.cpp
Go to the documentation of this file.
1 #include <fn.hpp>
2 #include <boost/date_time/gregorian/gregorian.hpp>
3 #include <iostream>
4 
5 /*
6 [ D ](https://wiki.dlang.org/Component_programming_with_ranges)
7 [ Rust ](https://gist.github.com/DanielKeep/7c87e697d5810803d069)
8 [ range-v3 ](https://github.com/ericniebler/range-v3/blob/master/example/calendar.cpp)
9 [ Haskell ](https://github.com/BartoszMilewski/Calendar/blob/master/Main.hs)
10 */
11 namespace greg = boost::gregorian;
12 using date_t = greg::date;
13 using dates_t = std::vector<date_t>;
14 
15 static void MakeCalendar(const uint16_t year,
16  const uint8_t num_months_horizontally,
17  std::ostream& ostr)
18 {
19  namespace fn = rangeless::fn;
20  using fn::operators::operator%;
21 
22  fn::seq([year, date = date_t( year, greg::Jan, 1 )]() mutable
23  {
24  auto ret = date;
25  date = date + greg::date_duration{ 1 };
26  return ret.year() == year ? ret : fn::end_seq();
27  })
28 
29  % fn::group_adjacent_by([](const date_t& d)
30  {
31  return std::make_pair(d.month(), d.week_number());
32  })
33 
34  // format a line for a week, e.g. " 1 2 3 4 5"
35  % fn::transform([&](dates_t wk_dates) -> std::pair<date_t::month_type, std::string>
36  {
37  const auto left_pad_amt =
38  size_t(3 * ((wk_dates.front().day_of_week() + 7 - 1) % 7));
39 
40  return { wk_dates.front().month(),
41  wk_dates % fn::foldl(std::string(left_pad_amt, ' '),
42  [](std::string ret_wk, const date_t& d)
43  {
44  return std::move(ret_wk)
45  + (d.day() < 10 ? " " : " ")
46  + std::to_string(d.day());
47  }) };
48  })
49 
50  % fn::group_adjacent_by(fn::by::first{}) // by month
51 
52  % fn::in_groups_of(num_months_horizontally)
53 
54  % fn::for_each([&](const auto& group) // group: vec<vec<(month, formatted-week-string)>>
55  {
56  static const std::array<std::string, 12> s_month_names{
57  "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
58 
59  for(int row = -2; row < 6; row++) { // month-name + weekdays-header + up to 6 week-lines
60  for(const auto& mo : group) {
61  ostr << std::setiosflags(std::ios::left)
62  << std::setw(25)
63  << ( row == -2 ? " " + s_month_names.at(mo.front().first - 1u)
64  : row == -1 ? " Mo Tu We Th Fr Sa Su"
65  : size_t(row) < mo.size() ? mo[row].second // formatted week
66  : " ");
67  }
68  ostr << "\n";
69  }
70  });
71 }
72 
73 int main()
74 {
75  MakeCalendar(2019, 3, std::cout);
76  return 0;
77 }
78 
79 /*
80 >>time g++ -O2 -I../include -std=gnu++14 -o calendar.cpp.o -c calendar.cpp
81 real 0m2.777s
82 user 0m2.484s
83 sys 0m0.275s
84 
85 Output:
86  Jan Feb Mar
87  Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
88  1 2 3 4 1 1
89  5 6 7 8 9 10 11 2 3 4 5 6 7 8 2 3 4 5 6 7 8
90  12 13 14 15 16 17 18 9 10 11 12 13 14 15 9 10 11 12 13 14 15
91  19 20 21 22 23 24 25 16 17 18 19 20 21 22 16 17 18 19 20 21 22
92  26 27 28 29 30 31 23 24 25 26 27 28 23 24 25 26 27 28 29
93  30 31
94 
95  Apr May Jun
96  Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
97  1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
98  6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
99  13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
100  20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
101  27 28 29 30 25 26 27 28 29 30 31 29 30
102 
103  Jul Aug Sep
104  Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
105  1 2 3 4 5 1 2 1 2 3 4 5 6
106  6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
107  13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
108  20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
109  27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
110  31
111 
112  Oct Nov Dec
113  Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su
114  1 2 3 4 1 1 2 3 4 5 6
115  5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
116  12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
117  19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
118  26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
119  30
120 
121 */
impl::group_adjacent_by< F > group_adjacent_by(F key_fn)
Group adjacent elements.
Definition: fn.hpp:4059
impl::group_adjacent_by< impl::chunker > in_groups_of(size_t n)
Group adjacent elements into chunks of specified size.
Definition: fn.hpp:4135
impl::foldl< Result, Op > foldl(Result init, Op binary_op)
Range-based version of c++20 (copy-free) std::accumulate
Definition: fn.hpp:3729
int main()
Definition: calendar.cpp:73
LINQ -like library of higher-order functions for data manipulation.
Definition: fn.hpp:58
Return fn::end_seq() from input-range generator function to signal end-of-inputs.
Definition: fn.hpp:281
impl::seq< impl::catch_end< NullaryInvokable > > seq(NullaryInvokable gen_fn)
Adapt a generator function as InputRange.
Definition: fn.hpp:677
static void MakeCalendar(const uint16_t year, const uint8_t num_months_horizontally, std::ostream &ostr)
Definition: calendar.cpp:15
impl::transform< F > transform(F map_fn)
Create a seq yielding results of applying the transform functions to input-elements.
Definition: fn.hpp:3670
std::vector< date_t > dates_t
Definition: calendar.cpp:13
impl::for_each< F > for_each(F fn)
Definition: fn.hpp:3811
greg::date date_t
Definition: calendar.cpp:12