I am exploring functional programming design with C++. The code below uses a struct passed to ranges::fold_left
for processing. The final result is returned in the struct.
**Updated to remove a toy
version of code since full code was requested and supplied
Is this an appropriate functional programming design? Specifically, using LineTotal
appropriate to maintain state information through the interactions of fold_left
used in extract_values
?
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <ranges>
#include "../AdventCpp.h"
namespace rng = std::ranges;
namespace vws = std::views;
//-------------------------------------------------------
execFunc execute = [ ](std::string_view&& aoc_data) noexcept -> uint64_t {
using vws::slide, vws::split, rng::fold_left, //
vws::take, vws::zip, vws::filter;
using std::string_view, std::string;
auto summation = [ ](uint64_t sum, auto&& aoc_dual) noexcept -> uint64_t {
auto top_line = string(string_view(aoc_dual.front()));
auto bottom_line = string(string_view(aoc_dual.next().front()));
// change dots to spaces so ispunct doesn't see dots
rng::replace(top_line, '.', ' ');
rng::replace(bottom_line, '.', ' ');
// generate container with pairs of chars from the two lines of data
auto zip_lines = zip(top_line, bottom_line);
// change dots to spaces so ispunct doesn't see dots
auto two_line_proc = [ ](uint64_t sum, auto&& lines) {
// some structs to pass data through fold_left
struct LineState {
uint64_t digits_sum { };
bool have_symbol { };
};
struct LineTotal {
uint64_t total { };
LineState top_data;
LineState bot_data;
};
auto out_sd = [&](char const tag, LineTotal s_d) {
auto [total, top, bot] = s_d;
std::cout << tag << '\t' << total << '\t' //
<< top.digits_sum << '\t' << top.have_symbol << '\t'
<< bot.digits_sum << '\t' << bot.have_symbol << '\n';
};
// is the value valid with symbols tagging it?
auto is_value = [ ](uint64_t value, bool symbol) noexcept -> uint64_t {
return (value != 0 and symbol) ? value : 0;
};
// calculate running value of digits from a line
auto calc_value = [ ](uint64_t value, char ch) noexcept -> uint64_t {
if (isdigit(ch)) {
value = value * 10 + (ch - '0');
}
return value;
};
auto extract_values =
[&is_value, &calc_value](LineTotal sum_data, auto&& two_char) {
auto [top_char, bot_char] = two_char;
auto& [total, top, bottom] = sum_data;
if (top_char == ' ' and ispunct(bot_char)) {
total += bottom.digits_sum;
total += top.digits_sum;
top = {0, true};
bottom = {0, true};
} else if (bot_char == ' ' and ispunct(top_char)) {
top = {top.digits_sum, true};
total += bottom.digits_sum;
bottom = {0, bottom.have_symbol};
} else if (top_char == ' ' and bot_char == ' ') {
total += is_value(top.digits_sum, bottom.have_symbol);
total += is_value(bottom.digits_sum,
top.have_symbol or bottom.have_symbol);
top = { };
bottom = { };
} else {
top = {calc_value(top.digits_sum, top_char),
top.have_symbol or ispunct(top_char)};
bottom = {calc_value(bottom.digits_sum, bot_char),
bottom.have_symbol or ispunct(bot_char)};
}
return sum_data;
};
// process two lines of aoc_data
return sum + fold_left(lines, LineTotal { }, extract_values).total;
};
return two_line_proc(sum, zip_lines);
};
return fold_left(aoc_data | split('\n') | slide(2), 0ul, summation);
};
int main() {
advent_cpp(test_data1, aoc_data, execute, 4361); // 4361 / 528799
return 0;
}