-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcaesar-cipher.cpp
More file actions
88 lines (78 loc) · 2.44 KB
/
caesar-cipher.cpp
File metadata and controls
88 lines (78 loc) · 2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iterator>
#include <numeric>
#include <stdexcept>
class caesar_rotator {
using char_table = std::array<char, UCHAR_MAX+1>;
const char_table table;
public:
caesar_rotator(int rotation) noexcept
: table{create_table(rotation)}
{}
char operator()(char c) const noexcept
{
return table[static_cast<unsigned char>(c)];
};
private:
static constexpr int upper_int(char c)
{
return std::toupper(static_cast<unsigned char>(c));
}
static constexpr char upper_char(char c)
{
return static_cast<char>(upper_int(c));
}
static char_table create_table(int rotation)
{
constexpr auto* letters = "abcdefghijklmnopqrstuvwxyz";
constexpr int len = std::strlen(letters);
// normalise to the smallest positive equivalent
rotation = (rotation % len + len) % len;
char_table table;
// begin with a identity mapping
std::iota(table.begin(), table.end(), 0);
// change the mapping of letters
for (auto i = 0, target = rotation; i < len; ++i, ++target) {
if (target == len) {
target = 0;
}
table[letters[i]] = letters[target];
table[upper_int(letters[i])] = upper_char(letters[target]);
}
return table;
}
};
int main(int argc, char **argv)
{
constexpr int default_rotation = 13;
// Parse arguments
int rotation;
if (argc <= 1) {
rotation = default_rotation;
} else if (argc == 2) {
try {
std::size_t end;
rotation = std::stoi(argv[1], &end);
if (argv[1][end]) { throw std::invalid_argument(""); }
} catch (...) {
std::cerr << "Invalid Caesar shift value: " << argv[1] << " (integer required)\n";
return EXIT_FAILURE;
}
} else {
std::cerr << "Usage: " << argv[0]
<< " [NUMBER]\nCaesar-shift letters in standard input by NUMBER places (default "
<< default_rotation <<")\n";
return EXIT_FAILURE;
}
// Now filter the input
std::transform(std::istreambuf_iterator<char>{std::cin},
std::istreambuf_iterator<char>{},
std::ostreambuf_iterator<char>{std::cout},
caesar_rotator{rotation});
}