Last active
May 3, 2016 05:58
-
-
Save elbeno/5c3ce7be27649f79f892db4db0617a9c to your computer and use it in GitHub Desktop.
Unfold formulations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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