mirror of
https://github.com/arun11299/cpp-jwt.git
synced 2025-05-14 16:58:34 +00:00
Base64 encoder decoder + Stack allocator
This commit is contained in:
parent
42e205a835
commit
b55cbe49c4
6 changed files with 444 additions and 0 deletions
183
include/jwt/base64.hpp
Normal file
183
include/jwt/base64.hpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
#ifndef CPP_JWT_BASE64_HPP
|
||||
#define CPP_JWT_BASE64_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
namespace jwt {
|
||||
|
||||
/*
|
||||
* Encoding map.
|
||||
*/
|
||||
class EMap
|
||||
{
|
||||
public:
|
||||
constexpr EMap() = default;
|
||||
|
||||
public:
|
||||
constexpr char at(size_t pos) const noexcept
|
||||
{
|
||||
assert (pos < chars_.size());
|
||||
return chars_.at(pos);
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<char, 64> chars_ = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
||||
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
|
||||
'0','1','2','3','4','5','6','7','8','9',
|
||||
'+','/',
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
std::string base64_encode(const char* in, size_t len)
|
||||
{
|
||||
std::string result;
|
||||
result.resize(128);
|
||||
|
||||
constexpr static const EMap bmap{};
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < len - 2; i += 3) {
|
||||
auto first = in[i];
|
||||
auto second = in[i+1];
|
||||
auto third = in[i+2];
|
||||
|
||||
result[i] = bmap.at( (first >> 2) & 0x3F );
|
||||
result[i + 1] = bmap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
|
||||
result[i + 2] = bmap.at(((second & 0x0F) << 2) | ((third & 0xC0) >> 6));
|
||||
result[i + 3] = bmap.at( (third & 0x3F) );
|
||||
}
|
||||
|
||||
switch (len % 3) {
|
||||
case 2:
|
||||
{
|
||||
auto first = in[i];
|
||||
auto second = in[i+1];
|
||||
|
||||
result[i] = bmap.at( (first >> 2) & 0x3F );
|
||||
result[i + 1] = bmap.at(((first & 0x03) << 4) | ((second & 0xF0) >> 4));
|
||||
result[i + 2] = bmap.at( (second & 0x0F) << 2 );
|
||||
result[i + 3] = '=';
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
auto& first = in[i];
|
||||
|
||||
result[i] = bmap.at((first >> 2) & 0x3F );
|
||||
result[i + 1] = bmap.at((first & 0x03) << 4 );
|
||||
result[i + 2] = '=';
|
||||
result[i + 3] = '=';
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
break;
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//======================= Decoder ==========================
|
||||
|
||||
/*
|
||||
* Decoding map.
|
||||
*/
|
||||
class DMap
|
||||
{
|
||||
public:
|
||||
constexpr DMap() = default;
|
||||
|
||||
public:
|
||||
constexpr char at(size_t pos) const noexcept
|
||||
{
|
||||
assert (pos < map_.size());
|
||||
return map_[pos];
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<char, 256> map_ = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0-15
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16-31
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, // 32-47
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 48-63
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, // 80-95
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240-255
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
std::string base64_decode(const char* in, size_t len)
|
||||
{
|
||||
std::string result;
|
||||
result.resize(128);
|
||||
int i = 0;
|
||||
size_t bytes_rem = len;
|
||||
|
||||
constexpr static const DMap dmap{};
|
||||
|
||||
while (dmap.at(in[bytes_rem - 1]) == -1) { bytes_rem--; }
|
||||
|
||||
while (bytes_rem > 4)
|
||||
{
|
||||
// Error case in input
|
||||
if (dmap.at(*in) == -1) return;
|
||||
|
||||
auto first = dmap.at(in[0]);
|
||||
auto second = dmap.at(in[1]);
|
||||
auto third = dmap.at(in[2]);
|
||||
auto fourth = dmap.at(in[3]);
|
||||
|
||||
result[i] = (first << 2) | (second >> 4);
|
||||
result[i + 1] = (second << 4) | (third >> 2);
|
||||
result[i + 2] = (third << 6) | fourth;
|
||||
|
||||
bytes_rem -= 4;
|
||||
i += 3;
|
||||
in += 4;
|
||||
}
|
||||
|
||||
switch(bytes_rem) {
|
||||
case 4:
|
||||
{
|
||||
auto third = dmap.at(in[2]);
|
||||
auto fourth = dmap.at(in[3]);
|
||||
result[i + 2] = (third << 6) | fourth;
|
||||
//FALLTHROUGH
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
auto second = dmap.at(in[1]);
|
||||
auto third = dmap.at(in[2]);
|
||||
result[i + 1] = (second << 4) | (third >> 2);
|
||||
//FALLTHROUGH
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
auto first = dmap.at(in[0]);
|
||||
auto second = dmap.at(in[1]);
|
||||
result[i] = (first << 2) | (second >> 4);
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
|
||||
#endif
|
BIN
include/jwt/impl/.stack_alloc.ipp.swp
Normal file
BIN
include/jwt/impl/.stack_alloc.ipp.swp
Normal file
Binary file not shown.
63
include/jwt/impl/stack_alloc.ipp
Normal file
63
include/jwt/impl/stack_alloc.ipp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef STACK_ALLOC_IPP
|
||||
#define STACK_ALLOC_IPP
|
||||
|
||||
namespace jwt {
|
||||
|
||||
template <size_t N, size_t alignment>
|
||||
template <size_t reqested_alignment>
|
||||
char* Arena<N, alignment>::allocate(size_t n) noexcept
|
||||
{
|
||||
static_assert (reqested_alignment <= alignment,
|
||||
"Requested alignment is too small for this arena");
|
||||
|
||||
assert (pointer_in_storage(ptr_) &&
|
||||
"No more space in the arena or it has outgrown its capacity");
|
||||
|
||||
n = align_up(n);
|
||||
|
||||
if ((ptr_ + n) <= (buf_ + N)) {
|
||||
char* ret = ptr_;
|
||||
ptr_ += n;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
assert (0 && "Code should not reach here");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <size_t N, size_t alignment>
|
||||
void Arena<N, alignment>::deallocate(char* p, size_t n) noexcept
|
||||
{
|
||||
assert (pointer_in_storage(p) &&
|
||||
"The address to de deleted does not lie inside the storage");
|
||||
|
||||
n = align_up(n);
|
||||
|
||||
if ((p + n) == ptr_) {
|
||||
ptr_ = p;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename T, size_t N, size_t alignment>
|
||||
T* stack_alloc<T, N, alignment>::allocate(size_t n) noexcept
|
||||
{
|
||||
return reinterpret_cast<T*>(
|
||||
arena_.template allocate<alignof(T)>(n * sizeof(T))
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T, size_t N, size_t alignment>
|
||||
void stack_alloc<T, N, alignment>::deallocate(T* p, size_t n) noexcept
|
||||
{
|
||||
arena_.deallocate(reinterpret_cast<char*>(p), n);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
176
include/jwt/stack_alloc.hpp
Normal file
176
include/jwt/stack_alloc.hpp
Normal file
|
@ -0,0 +1,176 @@
|
|||
#ifndef STACK_ALLOC_HPP
|
||||
#define STACK_ALLOC_HPP
|
||||
|
||||
/*
|
||||
* Based on Howard Hinnants awesome allocator boilerplate code
|
||||
* https://howardhinnant.github.io/short_alloc.h
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
|
||||
namespace jwt {
|
||||
|
||||
/*
|
||||
*/
|
||||
template <
|
||||
/// Size of the stack allocated byte buffer.
|
||||
size_t N,
|
||||
/// The alignment required for the buffer.
|
||||
size_t alignment = alignof(std::max_align_t)
|
||||
>
|
||||
class Arena
|
||||
{
|
||||
public: // 'tors
|
||||
Arena() noexcept
|
||||
: ptr_(buf_)
|
||||
{
|
||||
static_assert (alignment <= alignof(std::max_align_t),
|
||||
"Alignment chosen is more than the maximum supported alignment");
|
||||
}
|
||||
|
||||
/// Non copyable and assignable
|
||||
Arena(const Arena&) = delete;
|
||||
Arena& operator=(const Arena&) = delete;
|
||||
|
||||
~Arena()
|
||||
{
|
||||
ptr_ = nullptr;
|
||||
}
|
||||
|
||||
public: // Public APIs
|
||||
|
||||
/*
|
||||
* Reserves space within the buffer of size atleast 'n'
|
||||
* bytes.
|
||||
* More bytes maybe reserved based on the alignment requirements.
|
||||
*
|
||||
* Returns:
|
||||
* 1. The pointer within the storage buffer where the object can be constructed.
|
||||
* 2. nullptr if space cannot be reserved for requested number of bytes
|
||||
* (+ alignment padding if applicable)
|
||||
*/
|
||||
template <
|
||||
/// The requested alignment for this allocation.
|
||||
/// Must be less than or equal to the 'alignment'.
|
||||
size_t requested_alignment
|
||||
>
|
||||
char* allocate(size_t n) noexcept;
|
||||
|
||||
/*
|
||||
* Free back the space pointed by p within the storage buffer.
|
||||
*/
|
||||
void deallocate(char* p, size_t n) noexcept;
|
||||
|
||||
/*
|
||||
* The size of the internal storage buffer.
|
||||
*/
|
||||
constexpr static size_t size() noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns number of remaining bytes within the storage buffer
|
||||
* that can be used for further allocation requests.
|
||||
*/
|
||||
size_t used() const noexcept
|
||||
{
|
||||
return static_cast<size_t>(ptr_ - buf_);
|
||||
}
|
||||
|
||||
private: // Private member functions
|
||||
|
||||
/*
|
||||
* A check to determine if the pointer 'p'
|
||||
* points to a region within storage.
|
||||
*/
|
||||
bool pointer_in_storage(char* p) const noexcept
|
||||
{
|
||||
return (buf_ <= p) && (p <= (buf_ + N));
|
||||
}
|
||||
|
||||
/*
|
||||
* Rounds up the number to the next closest number
|
||||
* as per the alignment.
|
||||
*/
|
||||
constexpr static size_t align_up(size_t n) noexcept
|
||||
{
|
||||
return (n + (alignment - 1)) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
private: // data members
|
||||
/// Storage
|
||||
alignas(alignment) char buf_[N];
|
||||
|
||||
/// Current allocation pointer within storage
|
||||
char* ptr_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*/
|
||||
template <
|
||||
/// The allocator for type T
|
||||
typename T,
|
||||
/// Number of bytes for the arena
|
||||
size_t N,
|
||||
/// Alignment of the arena
|
||||
size_t align = alignof(std::max_align_t)
|
||||
>
|
||||
class stack_alloc
|
||||
{
|
||||
public: // typedefs
|
||||
using value_type = T;
|
||||
using arena_type = Arena<N, align>;
|
||||
|
||||
static auto constexpr alignment = align;
|
||||
static auto constexpr size = N;
|
||||
|
||||
public: // 'tors
|
||||
stack_alloc(arena_type& a)
|
||||
: arena_(a)
|
||||
{
|
||||
}
|
||||
|
||||
stack_alloc(const stack_alloc&) = default;
|
||||
stack_alloc& operator=(const stack_alloc&) = delete;
|
||||
|
||||
template <typename U>
|
||||
stack_alloc(const stack_alloc<U, N, alignment>& other)
|
||||
: arena_(other.arena_)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
struct rebind {
|
||||
using other = stack_alloc<U, N, alignment>;
|
||||
};
|
||||
|
||||
public: // Exposed APIs
|
||||
|
||||
/*
|
||||
* Allocate memory of 'n' bytes for object
|
||||
* of type 'T'
|
||||
*/
|
||||
T* allocate(size_t n) noexcept;
|
||||
|
||||
/*
|
||||
* Deallocate the storage reserved for the object
|
||||
* of type T pointed by pointer 'p'
|
||||
*/
|
||||
void deallocate(T* p, size_t n) noexcept;
|
||||
|
||||
private: // Private APIs
|
||||
|
||||
private: // Private data members
|
||||
/// The arena
|
||||
arena_type& arena_;
|
||||
};
|
||||
|
||||
} // END namespace jwt
|
||||
|
||||
#include "jwt/impl/stack_alloc.ipp"
|
||||
|
||||
#endif
|
BIN
include/jwt/test_stack_alloc
Executable file
BIN
include/jwt/test_stack_alloc
Executable file
Binary file not shown.
22
include/jwt/test_stack_alloc.cc
Normal file
22
include/jwt/test_stack_alloc.cc
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "./stack_alloc.hpp"
|
||||
|
||||
template <typename T, size_t SZ = 2>
|
||||
using SmallVector = std::vector<T, jwt::stack_alloc<T, SZ, alignof(T)>>;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
SmallVector<int>::allocator_type::arena_type a;
|
||||
SmallVector<int> v{a};
|
||||
|
||||
v.push_back(1);
|
||||
v.push_back(1);
|
||||
v.push_back(1);
|
||||
v.push_back(1);
|
||||
v.push_back(1);
|
||||
v.push_back(1);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue