Skip to content

Instantly share code, notes, and snippets.

@niXman
Last active February 17, 2024 13:22
Show Gist options
  • Save niXman/a6ae063335202d42c11f883493832df5 to your computer and use it in GitHub Desktop.
Save niXman/a6ae063335202d42c11f883493832df5 to your computer and use it in GitHub Desktop.
parse IP at compile-time
#include <array>
#include <iostream>
#include <cassert>
#include <cstring>
#include <cstdint>
#if !defined(__fallthrough) && defined(__has_cpp_attribute)
#if __has_cpp_attribute(fallthrough)
#define __FJ__FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define __FJ__FALLTHROUGH [[gnu::fallthrough]]
#endif
#endif
#if !defined(__FJ__FALLTHROUGH) && defined(__has_attribute)
#if __has_attribute(__fallthrough__)
#define __FJ__FALLTHROUGH __attribute__((__fallthrough__))
#endif
#endif
#if !defined(__FJ__FALLTHROUGH) /* well, we tried */
#define __FJ__FALLTHROUGH ((void)0)
#endif
constexpr const char* strchr(const char *s, char c) {
for ( ; *s && (*s != c); ++s )
;
return (*s) ? s : nullptr;
}
constexpr std::uint64_t atou64(const char *ptr, std::size_t len) {
# define __FJ__PER_CHAR_EXPR(n) ((res << 1) + (res << 3) + (str[len - n] - '0'))
const auto *str = reinterpret_cast<const std::uint8_t *>(ptr);
std::uint64_t res = 0;
switch ( len ) {
case 20: res = __FJ__PER_CHAR_EXPR(20); __FJ__FALLTHROUGH;
case 19: res = __FJ__PER_CHAR_EXPR(19); __FJ__FALLTHROUGH;
case 18: res = __FJ__PER_CHAR_EXPR(18); __FJ__FALLTHROUGH;
case 17: res = __FJ__PER_CHAR_EXPR(17); __FJ__FALLTHROUGH;
case 16: res = __FJ__PER_CHAR_EXPR(16); __FJ__FALLTHROUGH;
case 15: res = __FJ__PER_CHAR_EXPR(15); __FJ__FALLTHROUGH;
case 14: res = __FJ__PER_CHAR_EXPR(14); __FJ__FALLTHROUGH;
case 13: res = __FJ__PER_CHAR_EXPR(13); __FJ__FALLTHROUGH;
case 12: res = __FJ__PER_CHAR_EXPR(12); __FJ__FALLTHROUGH;
case 11: res = __FJ__PER_CHAR_EXPR(11); __FJ__FALLTHROUGH;
case 10: res = __FJ__PER_CHAR_EXPR(10); __FJ__FALLTHROUGH;
case 9 : res = __FJ__PER_CHAR_EXPR( 9); __FJ__FALLTHROUGH;
case 8 : res = __FJ__PER_CHAR_EXPR( 8); __FJ__FALLTHROUGH;
case 7 : res = __FJ__PER_CHAR_EXPR( 7); __FJ__FALLTHROUGH;
case 6 : res = __FJ__PER_CHAR_EXPR( 6); __FJ__FALLTHROUGH;
case 5 : res = __FJ__PER_CHAR_EXPR( 5); __FJ__FALLTHROUGH;
case 4 : res = __FJ__PER_CHAR_EXPR( 4); __FJ__FALLTHROUGH;
case 3 : res = __FJ__PER_CHAR_EXPR( 3); __FJ__FALLTHROUGH;
case 2 : res = __FJ__PER_CHAR_EXPR( 2); __FJ__FALLTHROUGH;
case 1 : res = __FJ__PER_CHAR_EXPR( 1);
}
# undef __FJ__PER_CHAR_EXPR
return res;
}
constexpr std::array<std::uint8_t, 4> split(const char *s, std::size_t slen, char sep = '.') {
std::array<std::uint8_t, 4> dst{};
std::uint8_t *d = dst.data();
const char *start = s;
for ( const char *p = strchr(s, sep); p; p = strchr(s, sep) ) {
std::size_t len = p-s;
*d++ = atou64(s, len);
s = p+1;
}
std::size_t len = slen - (s - start);
*d = atou64(s, len);
return dst;
}
#define TEST(exp, str, _0, _1, _2, _3) { \
constexpr auto ip = split(str, sizeof(str)-1); \
static_assert(ip[0] == _0); \
static_assert(ip[1] == _1); \
static_assert(ip[2] == _2); \
static_assert(ip[3] == _3); \
std::cout << "expression \"" str "\" parsed as " << (std::size_t)ip[0] << '.' << (std::size_t)ip[1] << '.' << (std::size_t)ip[2] << '.' << (std::size_t)ip[3] << std::endl; \
}
int main() {
TEST(true, "0.0.0.0", 0, 0, 0, 0)
TEST(true, "1.1.1.1", 1, 1, 1, 1)
TEST(true, "10.10.10.10", 10, 10, 10, 10)
TEST(true, "11.11.11.11", 11, 11, 11, 11)
TEST(true, "110.110.110.110", 110, 110, 110, 110)
TEST(false, "0", 0, 0, 0, 0)
//TEST(false, "0:0:0:0", 0, 0, 0, 0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment