Last active
March 1, 2016 11:53
-
-
Save tfc/5a3a8355546f2962fa25 to your computer and use it in GitHub Desktop.
Iterator experiment with use case of base64 encoding
This file contains 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 <iostream> | |
#include <assert.h> | |
// This one vanishes in library | |
template <typename T, typename DerefT> | |
class iterator_facade | |
{ | |
T& thisT() { return static_cast< T&>(*this); } | |
const T& thisT() const { return static_cast<const T&>(*this); } | |
public: | |
DerefT operator* () const { return thisT().deref(); } | |
DerefT operator->() const { return thisT().deref(); } | |
T& operator++() { thisT().preincrement(); return thisT(); } | |
T& operator++(int) { T ret{thisT()}; thisT().preincrement(); return ret; } | |
// operator== must be implemented by T | |
bool operator!=(const T& o) { return !(thisT() == o); } | |
}; | |
// implementation part | |
class triple_byte_it : public iterator_facade<triple_byte_it, unsigned> | |
{ | |
const char *current; | |
const char *post_last; | |
public: | |
void preincrement() { current += 3; } | |
unsigned deref() const { | |
unsigned ret {0}; | |
memcpy(&ret, current, std::min<unsigned>(3, post_last - current)); | |
return ret; | |
} | |
bool operator==(const triple_byte_it &o) const { return current == o.current; } | |
triple_byte_it(const char *start, const char *end_) | |
: current{start}, post_last{end_} | |
{} | |
}; | |
template <typename T> | |
class output_width_it : public iterator_facade<output_width_it<T>, T&> | |
{ | |
char *current; | |
const char *post_last; | |
public: | |
void preincrement() { current += sizeof(T); } | |
T& deref() const { return *reinterpret_cast<T*>(current); } | |
bool operator==(const output_width_it &o) const { return current == o.current; } | |
output_width_it(char *start) : current{start} {} | |
}; | |
class triple_input_itr | |
{ | |
const char *a; | |
const char *b_pad; | |
const char *b; | |
public: | |
triple_input_itr(const char *a_, const char *b_pad_, const char *b_real_) : a{a_}, b_pad{b_pad_}, b{b_real_} {} | |
triple_byte_it begin() const { return {a, b}; } | |
triple_byte_it end() const { return {b_pad, b}; } | |
}; | |
class quad_output_itr | |
{ | |
char *a; | |
char *b; | |
public: | |
quad_output_itr(char *a_, char *b_) : a{a_}, b{b_} {} | |
output_width_it<unsigned> begin() const { return {a}; } | |
output_width_it<unsigned> end() const { return {b}; } | |
}; | |
static unsigned convert(unsigned in) | |
{ | |
static constexpr char map[] {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}; | |
static_assert(sizeof(map) == 64 + 1, "Error in map"); | |
char out[4]; | |
in = (0xff & (in >> 16)) | (0xff00 & in) | ((0xff & in) << 16); | |
for (size_t i {0}; i < 4; ++i) { | |
const char chunk {char(0x3f & (in >> (6 * i)))}; | |
assert(chunk < 64); | |
out[3 - i] = map[chunk]; | |
} | |
return *reinterpret_cast<unsigned*>(&out[0]); | |
} | |
void base64_enc(const char *in_buf, char *out_buf) | |
{ | |
const size_t in_len {strlen(in_buf)}; | |
const size_t in_len_pad {(strlen(in_buf) + 2) / 3 * 3}; | |
const size_t out_len {in_len * 4 / 3}; | |
const size_t out_len_pad {in_len_pad / 3 * 4}; | |
const size_t pad_bytes {in_len_pad - in_len}; | |
triple_input_itr in {&in_buf[0], &in_buf[in_len_pad], &in_buf[in_len]}; | |
quad_output_itr out {&out_buf[0], &out_buf[out_len_pad]}; | |
std::transform(in.begin(), in.end(), out.begin(), convert); | |
std::fill(&out_buf[out_len + 1], &out_buf[out_len + 1 + pad_bytes], '='); | |
out_buf[out_len + 1 + pad_bytes] = '\0'; | |
}; | |
int main() | |
{ | |
char in_buf [] = "any carnal pleasure."; | |
char out_buf[1000]; | |
// Checking against examples from https://en.wikipedia.org/wiki/Base64 | |
base64_enc("any carnal pleasure.", out_buf); | |
assert(0 == strcmp(out_buf, "YW55IGNhcm5hbCBwbGVhc3VyZS4=")); | |
base64_enc("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.", out_buf); | |
assert(0 == strcmp(out_buf, "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=")); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment