Skip to content

Instantly share code, notes, and snippets.

@elbeno
Last active May 3, 2016 05:58
Show Gist options
  • Save elbeno/5c3ce7be27649f79f892db4db0617a9c to your computer and use it in GitHub Desktop.
Save elbeno/5c3ce7be27649f79f892db4db0617a9c to your computer and use it in GitHub Desktop.
Unfold formulations
#include <algorithm>
#include <cassert>
#include <iostream>
#include <iterator>
#include <map>
#include <numeric>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
template <int N>
int addN(int i) { return i + N; }
template <int N>
int multN(int i) { return i * N; }
template <int A, int B>
int promote(int i) { auto r = i%A; return (i-r) + (B*r); }
using F = int (*)(int);
map<string, F> from_word =
{
{ "one", addN<1> },
{ "two", addN<2> },
{ "three", addN<3> },
{ "four", addN<4> },
{ "five", addN<5> },
{ "six", addN<6> },
{ "seven", addN<7> },
{ "eight", addN<8> },
{ "nine", addN<9> },
{ "ten", addN<10> },
{ "eleven", addN<11> },
{ "twelve", addN<12> },
{ "thirteen", addN<13> },
{ "fourteen", addN<14> },
{ "fifteen", addN<15> },
{ "sixteen", addN<16> },
{ "seventeen", addN<17> },
{ "eighteen", addN<18> },
{ "nineteen", addN<19> },
{ "twenty", addN<20> },
{ "thirty", addN<30> },
{ "fourty", addN<40> },
{ "fifty", addN<50> },
{ "sixty", addN<60> },
{ "seventy", addN<70> },
{ "eighty", addN<80> },
{ "ninety", addN<90> },
{ "hundred", promote<1000, 100> },
{ "thousand", promote<1000000, 1000> },
{ "million", promote<1000000000, 1000000> },
{ "billion", multN<1000000000> }
};
template <typename FwdIt, typename T, typename F>
FwdIt unfold(F&& f, FwdIt it, T&& init, T&& term)
{
auto p = f(std::forward<T>(init));
*it++ = std::move(p.first);
while (p.second != term) {
p = f(p.second);
*it++ = std::move(p.first);
}
return it;
}
map<int, string> to_word = {
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 4, "four" },
{ 5, "five" },
{ 6, "six" },
{ 7, "seven" },
{ 8, "eight" },
{ 9, "nine" },
{ 10, "ten" },
{ 11, "eleven" },
{ 12, "twelve" },
{ 13, "thirteen" },
{ 14, "fourteen" },
{ 15, "fifteen" },
{ 16, "sixteen" },
{ 17, "seventeen" },
{ 18, "eighteen" },
{ 19, "nineteen" },
{ 20, "twenty" },
{ 30, "thirty" },
{ 40, "forty" },
{ 50, "fifty" },
{ 60, "sixty" },
{ 70, "seventy" },
{ 80, "eighty" },
{ 90, "ninety" }
};
map<int, string> mult_word = {
{ 0, "thousand" },
{ 1, "million" },
{ 2, "billion" }
};
struct to_word_helper
{
int mult = 0;
pair<string, int> operator()(int n)
{
auto r = n % 100;
if (r > 0) {
if (r < 21) return { to_word[r], n - r }; // teens
auto u = n % 10;
if (u > 0) return { to_word[u], n - u }; // units
return { to_word[r], n - r }; // tens
}
r = n % 1000;
if (r > 0) return { to_word[r/100] + " hundred", n - r };
return { mult_word[mult++], n/1000 };
}
};
int main(void)
{
string input = "one billion two hundred thirty four million "
"five hundred sixty seven thousand eight hundred ninety";
vector<string> words;
stringstream iss(input);
for (string s; getline(iss, s, ' '); words.push_back(s));
int n = accumulate(words.cbegin(), words.cend(), 0,
[] (int acc, const string& word) {
auto f = from_word.find(word);
if (f != from_word.end()) {
return f->second(acc);
}
return acc;
});
cout << n << endl;
words.clear();
unfold(to_word_helper{}, back_inserter(words), 1234567890, 0);
string output = accumulate(next(words.crbegin()), words.crend(), *words.crbegin(),
[] (const string& s, const string& w) {
return s + " " + w;
});
cout << output << endl;
assert(input == output);
}
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
#ifndef _MSC_VER
#include <experimental/optional>
#endif
using namespace std;
#if _MSC_VER < 1900
template <typename...> using void_t = void;
#endif
template <typename I, typename V, typename = void>
struct iter_assignable : std::false_type {};
template <typename I, typename V>
struct iter_assignable<I, V,
void_t<decltype(*declval<I>() = declval<V>())>> : std::true_type {};
// -----------------------------------------------------------------------------
// unfold with termination on first value
template <typename FwdIt, typename T, typename F,
typename U = decltype(declval<std::result_of_t<F(T)>>().first)>
FwdIt unfold(F&& f, FwdIt it, T&& init, U&& term,
std::enable_if_t<iter_assignable<FwdIt, U>::value>* = nullptr)
{
T t{std::forward<T>(init)};
for (auto p = f(t); p.first != term; p = f(p.second)) {
*it++ = p.first;
}
return it;
}
template <typename FwdIt, typename T, typename F,
typename U = decltype(declval<std::result_of_t<F(T)>>().first)>
FwdIt unfold(F&& f, FwdIt it, T&& init, U&& term,
std::enable_if_t<!iter_assignable<FwdIt, U>::value>* = nullptr)
{
T t{std::forward<T>(init)};
for (auto p = f(t); p.first != term; p = f(p.second)) {
it = std::move(std::begin(p.first), std::end(p.first), it);
}
return it;
}
pair<string, int> to_roman(int n)
{
if (n >= 1000) return { "M", n-1000 };
if (n >= 900) return { "CM", n-900 };
if (n >= 500) return { "D", n-500 };
if (n >= 400) return { "CD", n-400 };
if (n >= 100) return { "C", n-100 };
if (n >= 90) return { "XC", n-90 };
if (n >= 50) return { "L", n-50 };
if (n >= 40) return { "XL", n-40 };
if (n >= 10) return { "X", n-10 };
if (n >= 9) return { "IX", n-9 };
if (n >= 5) return { "V", n-5 };
if (n >= 4) return { "IV", n-4 };
if (n >= 1) return { "I", n-1 };
return { string{}, 0 };
}
pair<char, int> to_arabic(int n)
{
if (n == 0) return { '\0', 0 };
return { static_cast<char>('0' + n%10), n/10 };
}
// -----------------------------------------------------------------------------
// unfold with termination on second value
template <typename FwdIt, typename T, typename F,
typename U = decltype(declval<std::result_of_t<F(T)>>().first)>
FwdIt unfold1(F&& f, FwdIt it, T&& init, T&& term,
std::enable_if_t<iter_assignable<FwdIt, U>::value>* = nullptr)
{
auto p = f(std::forward<T>(init));
*it++ = p.first;
while (p.second != term) {
p = f(p.second);
*it++ = p.first;
}
return it;
}
template <typename FwdIt, typename T, typename F,
typename U = decltype(declval<std::result_of_t<F(T)>>().first)>
FwdIt unfold1(F&& f, FwdIt it, T&& init, T&& term,
std::enable_if_t<!iter_assignable<FwdIt, U>::value>* = nullptr)
{
auto p = f(std::forward<T>(init));
it = std::move(std::begin(p.first), std::end(p.first), it);
while (p.second != term) {
p = f(p.second);
it = std::move(std::begin(p.first), std::end(p.first), it);
}
return it;
}
pair<char, int> to_arabic1(int n)
{
return { static_cast<char>('0' + n%10), n/10 };
}
// -----------------------------------------------------------------------------
// unfold with termination on optional
#ifndef _MSC_VER
template <typename FwdIt, typename T, typename F,
typename U = decltype(declval<typename std::result_of_t<F(T)>::value_type>().first)>
FwdIt unfold2(F&& f, FwdIt it, T&& init,
std::enable_if_t<iter_assignable<FwdIt, U>::value>* = nullptr)
{
T t{std::forward<T>(init)};
for (auto o = f(t); o; o = f(o->second)) {
*it++ = o->first;
}
return it;
}
template <typename FwdIt, typename T, typename F,
typename U = decltype(declval<typename std::result_of_t<F(T)>::value_type>().first)>
FwdIt unfold2(F&& f, FwdIt it, T&& init,
std::enable_if_t<!iter_assignable<FwdIt, U>::value>* = nullptr)
{
T t{std::forward<T>(init)};
for (auto o = f(t); o; o = f(o->second)) {
it = std::move(std::begin(o->first), std::end(o->first), it);
}
return it;
}
experimental::optional<pair<string, int>> to_roman2(int n)
{
if (n >= 1000) return {{ "M", n-1000 }};
if (n >= 900) return {{ "CM", n-900 }};
if (n >= 500) return {{ "D", n-500 }};
if (n >= 400) return {{ "CD", n-400 }};
if (n >= 100) return {{ "C", n-100 }};
if (n >= 90) return {{ "XC", n-90 }};
if (n >= 50) return {{ "L", n-50 }};
if (n >= 40) return {{ "XL", n-40 }};
if (n >= 10) return {{ "X", n-10 }};
if (n >= 9) return {{ "IX", n-9 }};
if (n >= 5) return {{ "V", n-5 }};
if (n >= 4) return {{ "IV", n-4 }};
if (n >= 1) return {{ "I", n-1 }};
return experimental::nullopt;
}
experimental::optional<pair<char, int>> to_arabic2(int n)
{
if (n == 0) return experimental::nullopt;
return {{ static_cast<char>('0' + n%10), n/10 }};
}
#endif
int main(void)
{
{
string r;
unfold(to_roman, back_inserter(r), 1974, string{});
cout << r << endl;
}
{
string r;
unfold1(to_roman, back_inserter(r), 1974, 0);
cout << r << endl;
}
#ifndef _MSC_VER
{
string r;
unfold2(to_roman2, back_inserter(r), 1974);
cout << r << endl;
}
#endif
{
char buf[16];
auto i = rbegin(buf);
*i++ = '\0';
const char* num = unfold(to_arabic, i, 1234567890, '\0').base();
cout << num << endl;
}
{
char buf[16];
auto i = rbegin(buf);
*i++ = '\0';
const char* num = unfold1(to_arabic1, i, 1234567890, 0).base();
cout << num << endl;
}
#ifndef _MSC_VER
{
char buf[16];
auto i = rbegin(buf);
*i++ = '\0';
const char* num = unfold2(to_arabic2, i, 1234567890).base();
cout << num << endl;
}
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment