Skip to content

Instantly share code, notes, and snippets.

@tfc
Last active March 1, 2016 11:53
Show Gist options
  • Save tfc/5a3a8355546f2962fa25 to your computer and use it in GitHub Desktop.
Save tfc/5a3a8355546f2962fa25 to your computer and use it in GitHub Desktop.
Iterator experiment with use case of base64 encoding
#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