Skip to content

Instantly share code, notes, and snippets.

@pkhuong
Last active May 24, 2020 00:27
Show Gist options
  • Save pkhuong/8e575dcade519d42436a302e9c8a5844 to your computer and use it in GitHub Desktop.
Save pkhuong/8e575dcade519d42436a302e9c8a5844 to your computer and use it in GitHub Desktop.
BridgeTC: a bridge from C types to C singleton values
/* -*- mode: C -*- */
#if BRIDGETC_IMPL_DIGIT_1 == 0
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 1
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_1
#elif BRIDGETC_IMPL_DIGIT_1 == 1
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 2
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_2
#elif BRIDGETC_IMPL_DIGIT_1 == 2
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 3
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_3
#elif BRIDGETC_IMPL_DIGIT_1 == 3
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 4
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_4
#elif BRIDGETC_IMPL_DIGIT_1 == 4
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 5
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_5
#elif BRIDGETC_IMPL_DIGIT_1 == 5
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 6
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_6
#elif BRIDGETC_IMPL_DIGIT_1 == 6
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 7
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_7
#elif BRIDGETC_IMPL_DIGIT_1 == 7
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 8
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_8
#elif BRIDGETC_IMPL_DIGIT_1 == 8
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 9
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_9
#elif BRIDGETC_IMPL_DIGIT_1 == 9
# undef BRIDGETC_IMPL_DIGIT_1
# define BRIDGETC_IMPL_DIGIT_1 0
# undef BRIDGETC_IMPL_SEARCH_1
# define BRIDGETC_IMPL_SEARCH_1 BRIDGETC_IMPL_SEARCH_1_0
# include "bridgetc_digit_update_2.inc"
#endif
/* -*- mode: C -*- */
#if BRIDGETC_IMPL_DIGIT_2 == 0
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 1
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_1
#elif BRIDGETC_IMPL_DIGIT_2 == 1
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 2
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_2
#elif BRIDGETC_IMPL_DIGIT_2 == 2
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 3
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_3
#elif BRIDGETC_IMPL_DIGIT_2 == 3
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 4
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_4
#elif BRIDGETC_IMPL_DIGIT_2 == 4
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 5
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_5
#elif BRIDGETC_IMPL_DIGIT_2 == 5
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 6
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_6
#elif BRIDGETC_IMPL_DIGIT_2 == 6
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 7
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_7
#elif BRIDGETC_IMPL_DIGIT_2 == 7
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 8
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_8
#elif BRIDGETC_IMPL_DIGIT_2 == 8
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 9
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_9
#elif BRIDGETC_IMPL_DIGIT_2 == 9
# undef BRIDGETC_IMPL_DIGIT_2
# define BRIDGETC_IMPL_DIGIT_2 0
# undef BRIDGETC_IMPL_SEARCH_2
# define BRIDGETC_IMPL_SEARCH_2 BRIDGETC_IMPL_SEARCH_2_0
# error "BTC mapping limit exceeded (999)"
#endif
#pragma once
#define BRIDGETC_IMPL_NEXT BRIDGETC_IMPL_ID(BRIDGETC_IMPL_DIGIT_2, BRIDGETC_IMPL_DIGIT_1, BRIDGETC_IMPL_DIGIT_0)
#define BRIDGETC_IMPL_ID(BTC_V0, BTC_V1, BTC_V2) BRIDGETC_IMPL_ID_(BTC_V0, BTC_V1, BTC_V2)
#define BRIDGETC_IMPL_ID_(BTC_V0, BTC_V1, BTC_V2) BTC_value_##BTC_V0##BTC_V1##BTC_V2
#define BRIDGETC_IMPL_DIGIT_0 0
#define BRIDGETC_IMPL_SEARCH_0(BTC_X, BTC_DEFAULT) BTC_DEFAULT
#define BRIDGETC_IMPL_DIGIT_1 0
#define BRIDGETC_IMPL_SEARCH_1(BTC_X, BTC_DEFAULT) BTC_DEFAULT
#define BRIDGETC_IMPL_DIGIT_2 0
#define BRIDGETC_IMPL_SEARCH_2(BTC_X, BTC_DEFAULT) BTC_DEFAULT
#define BRIDGETC_IMPL_SEARCH(BTC_X, BTC_DEFAULT, ...) \
BRIDGETC_IMPL_SEARCH_0(BTC_X, \
BRIDGETC_IMPL_SEARCH_1(BTC_X, \
BRIDGETC_IMPL_SEARCH_2(BTC_X, BTC_DEFAULT)))
#define BTC_SEARCH(BTC_X, ...) BRIDGETC_IMPL_SEARCH(__typeof__(BTC_X), ##__VA_ARGS__, (void)0)
#define BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, BTC_V0, BTC_DEFAULT) \
__builtin_choose_expr( \
__builtin_types_compatible_p(BTC_X, \
__typeof__(BRIDGETC_IMPL_ID(BTC_V2, BTC_V1, BTC_V0))), \
BRIDGETC_IMPL_ID(BTC_V2, BTC_V1, BTC_V0), BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_0_(BTC_X, BTC_V0, BTC_DEFAULT) \
BRIDGETC_IMPL_TEST_0(BTC_X, BRIDGETC_IMPL_DIGIT_2, BRIDGETC_IMPL_DIGIT_1, BTC_V0, BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_0_0(BTC_X, BTC_DEFAULT) \
BTC_DEFAULT
#define BRIDGETC_IMPL_SEARCH_0_1(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_0_2(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT))
#define BRIDGETC_IMPL_SEARCH_0_3(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT)))
#define BRIDGETC_IMPL_SEARCH_0_4(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT))))
#define BRIDGETC_IMPL_SEARCH_0_5(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT)))))
#define BRIDGETC_IMPL_SEARCH_0_6(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT))))))
#define BRIDGETC_IMPL_SEARCH_0_7(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT)))))))
#define BRIDGETC_IMPL_SEARCH_0_8(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 7, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT))))))))
#define BRIDGETC_IMPL_SEARCH_0_9(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 8, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 7, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_0_(BTC_X, 0, \
BTC_DEFAULT)))))))))
#define BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, BTC_V1, BTC_DEFAULT) \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 0, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 1, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 2, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 3, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 4, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 5, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 6, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 7, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 8, \
BRIDGETC_IMPL_TEST_0(BTC_X, BTC_V2, BTC_V1, 9, \
BTC_DEFAULT))))))))))
#define BRIDGETC_IMPL_SEARCH_1_(BTC_X, BTC_V1, BTC_DEFAULT) \
BRIDGETC_IMPL_TEST_1(BTC_X, BRIDGETC_IMPL_DIGIT_2, BTC_V1, BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_1_0(BTC_X, BTC_DEFAULT) \
BTC_DEFAULT
#define BRIDGETC_IMPL_SEARCH_1_1(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_1_2(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT))
#define BRIDGETC_IMPL_SEARCH_1_3(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT)))
#define BRIDGETC_IMPL_SEARCH_1_4(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT))))
#define BRIDGETC_IMPL_SEARCH_1_5(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT)))))
#define BRIDGETC_IMPL_SEARCH_1_6(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT))))))
#define BRIDGETC_IMPL_SEARCH_1_7(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT)))))))
#define BRIDGETC_IMPL_SEARCH_1_8(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 7, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT))))))))
#define BRIDGETC_IMPL_SEARCH_1_9(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 8, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 7, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_1_(BTC_X, 0, \
BTC_DEFAULT)))))))))
#define BRIDGETC_IMPL_TEST_2(BTC_X, BTC_V2, BTC_DEFAULT) \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 0, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 1, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 2, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 3, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 4, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 5, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 6, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 7, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 8, \
BRIDGETC_IMPL_TEST_1(BTC_X, BTC_V2, 9, \
BTC_DEFAULT))))))))))
#define BRIDGETC_IMPL_SEARCH_2_(BTC_X, BTC_V2, BTC_DEFAULT) \
BRIDGETC_IMPL_TEST_2(BTC_X, BTC_V2, BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_2_0(BTC_X, BTC_DEFAULT) \
BTC_DEFAULT
#define BRIDGETC_IMPL_SEARCH_2_1(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT)
#define BRIDGETC_IMPL_SEARCH_2_2(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT))
#define BRIDGETC_IMPL_SEARCH_2_3(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT)))
#define BRIDGETC_IMPL_SEARCH_2_4(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT))))
#define BRIDGETC_IMPL_SEARCH_2_5(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT)))))
#define BRIDGETC_IMPL_SEARCH_2_6(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT))))))
#define BRIDGETC_IMPL_SEARCH_2_7(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT)))))))
#define BRIDGETC_IMPL_SEARCH_2_8(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 7, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT))))))))
#define BRIDGETC_IMPL_SEARCH_2_9(BTC_X, BTC_DEFAULT) \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 8, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 7, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 6, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 5, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 4, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 3, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 2, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 1, \
BRIDGETC_IMPL_SEARCH_2_(BTC_X, 0, \
BTC_DEFAULT)))))))))
/* -*- mode: C -*- */
#include "bridgetc_prologue.h"
#pragma GCC diagnostic push
#ifndef __clang__
# pragma GCC diagnostic ignored "-Wold-style-declaration"
#endif
} static const __attribute__((__unused__)) BRIDGETC_IMPL_NEXT;
#pragma GCC diagnostic pop
_Static_assert(__builtin_types_compatible_p(void, \
__typeof__(BTC_SEARCH(BRIDGETC_IMPL_NEXT))), \
"Only one singleton may be associated with each type.");
static __typeof__(BRIDGETC_IMPL_NEXT) BRIDGETC_IMPL_NEXT = {
#if BRIDGETC_IMPL_DIGIT_0 == 0
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 1
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_1
#elif BRIDGETC_IMPL_DIGIT_0 == 1
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 2
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_2
#elif BRIDGETC_IMPL_DIGIT_0 == 2
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 3
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_3
#elif BRIDGETC_IMPL_DIGIT_0 == 3
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 4
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_4
#elif BRIDGETC_IMPL_DIGIT_0 == 4
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 5
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_5
#elif BRIDGETC_IMPL_DIGIT_0 == 5
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 6
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_6
#elif BRIDGETC_IMPL_DIGIT_0 == 6
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 7
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_7
#elif BRIDGETC_IMPL_DIGIT_0 == 7
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 8
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_8
#elif BRIDGETC_IMPL_DIGIT_0 == 8
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 9
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_9
#elif BRIDGETC_IMPL_DIGIT_0 == 9
# undef BRIDGETC_IMPL_DIGIT_0
# define BRIDGETC_IMPL_DIGIT_0 0
# undef BRIDGETC_IMPL_SEARCH_0
# define BRIDGETC_IMPL_SEARCH_0 BRIDGETC_IMPL_SEARCH_0_0
# include "bridgetc_digit_update_1.inc"
#endif
#!/usr/bin/env python3
# Generator for type singletons in C.
#
# Let's say you have a data structure with some extensible behaviour
# (e.g., user-defined hashing and equality testing functions). One
# might use a vtable, but, in most cases, the calling code isn't
# late-bound: while containers might be type-generic, their users
# rarely are, in C.
#
# Ideally, we would have something like a vtable, except without any
# per-instance space usage overhead, and, ideally, transparent enough
# for C compilers to optimise away the indirection.
#
# That's what B(ridge)TC provides: a way to encode references to C
# variables in *C types*, and a conversion back from these types to
# the variables' values, all optimised away at compile-time.
#
# With apologies to Helen Fielding and her famous singleton, Bridget.
# The generator, as well as its output, is MIT Licensed.
#
# Copyright 2020 Paul Khuong
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
FILE_PREFIX = "bridgetc"
IMPL = "BRIDGETC_IMPL"
NS = "BTC"
# We increment in CPP by storing different digits in different
# variables, and updating each with an #if ladder.
# Spread our state across 3 variables, which lets us count to 998
# (there's an off by one that's not worth fixing).
NUM_DIGITS = 3
# And count in radix 10; make this lower to have an easier time
# testing higher digit counts.
RADIX = 10
assert RADIX <= 10, "Pasting digits stops working above 10"
IDENTIFIERS = [f"{NS}_V{i}" for i in range(NUM_DIGITS)]
DIGIT_VARS = [f"{IMPL}_DIGIT_{i}" for i in range(NUM_DIGITS)]
def enumerate_search_cases(digit, out):
acc = f"{NS}_DEFAULT"
for i in range(RADIX):
print(
f"""\
#define {IMPL}_SEARCH_{digit}_{i}({NS}_X, {NS}_DEFAULT) \\
{acc}
""",
file=out,
)
acc = f"{IMPL}_SEARCH_{digit}_({NS}_X, {i},\t\\\n\t{acc})"
def generate_prologue(path=f"{FILE_PREFIX}_prologue.h"):
id_list = ", ".join(IDENTIFIERS)
with open(path, "w") as out:
print(
f"""\
#pragma once
#define {IMPL}_NEXT {IMPL}_ID({", ".join(reversed(DIGIT_VARS))})
#define {IMPL}_ID({id_list}) {IMPL}_ID_({id_list})
#define {IMPL}_ID_({id_list}) {NS}_value_##{"##".join(IDENTIFIERS)}
""",
file=out,
)
for i in range(NUM_DIGITS):
print(f"#define {IMPL}_DIGIT_{i} 0", file=out)
print(
f"#define {IMPL}_SEARCH_{i}({NS}_X, {NS}_DEFAULT) {NS}_DEFAULT",
file=out,
)
# The __builtin_types_compatible_p implementation needs to
# nest these search macros. The implementation is a bit nicer
# with _Generic.
search_expr = (
"\\\n\t".join(f"{IMPL}_SEARCH_{i}({NS}_X, " for i in range(NUM_DIGITS))
+ f"{NS}_DEFAULT"
+ NUM_DIGITS * ")"
)
print(
f"""
#define {IMPL}_SEARCH({NS}_X, {NS}_DEFAULT, ...) \\
{search_expr}
#define {NS}_SEARCH({NS}_X, ...) {IMPL}_SEARCH(__typeof__({NS}_X), ##__VA_ARGS__, (void)0)
""",
file=out,
)
# Base case for the __builtin_types_compatible_p search.
rident = ", ".join(reversed(IDENTIFIERS))
digits = list(reversed(DIGIT_VARS[1:]))
var = IDENTIFIERS[0]
print(
f"""\
#define {IMPL}_TEST_0({NS}_X, {rident}, {NS}_DEFAULT) \\
__builtin_choose_expr( \\
__builtin_types_compatible_p({NS}_X, \\
__typeof__({IMPL}_ID({rident}))), \\
{IMPL}_ID({rident}), {NS}_DEFAULT)
#define {IMPL}_SEARCH_0_({NS}_X, {var}, {NS}_DEFAULT) \\
{IMPL}_TEST_0({NS}_X, {", ".join(digits + [var])}, {NS}_DEFAULT)
""",
file=out,
)
enumerate_search_cases(0, out)
for i in range(1, NUM_DIGITS):
variant = list(reversed(IDENTIFIERS[i:]))
digits = list(reversed(DIGIT_VARS[i + 1 :]))
var = IDENTIFIERS[i]
prev_test = f"{IMPL}_TEST_{i - 1}"
acc = f"{NS}_DEFAULT"
for enumerated in reversed(range(RADIX)):
args = ", ".join(variant + [str(enumerated)])
acc = f"{prev_test}({NS}_X, {args},\t\\\n\t{acc})"
print(
f"""\
#define {IMPL}_TEST_{i}({NS}_X, {", ".join(variant)}, {NS}_DEFAULT) \\
{acc}
#define {IMPL}_SEARCH_{i}_({NS}_X, {var}, {NS}_DEFAULT) \\
{IMPL}_TEST_{i}({NS}_X, {", ".join(digits + [var])}, {NS}_DEFAULT)
""",
file=out,
)
enumerate_search_cases(i, out)
generate_prologue()
def generate_digit_update(digit, out):
var = f"{IMPL}_DIGIT_{digit}"
search = f"{IMPL}_SEARCH_{digit}"
conditional = "if"
for i in range(RADIX):
succ = (i + 1) % RADIX
print(
f"""\
#{conditional} {var} == {i}
# undef {var}
# define {var} {succ}
# undef {search}
# define {search} {search}_{succ}\
""",
file=out,
)
conditional = "elif"
next_digit = digit + 1
if next_digit == NUM_DIGITS:
print(
f"""# error "BTC mapping limit exceeded ({RADIX ** NUM_DIGITS - 1})"\
""",
file=out,
)
else:
print(
f"""# include "{FILE_PREFIX}_digit_update_{next_digit}.inc"\
""",
file=out,
)
print("#endif", file=out)
for digit in range(1, NUM_DIGITS):
with open(f"{FILE_PREFIX}_digit_update_{digit}.inc", "w") as out:
print("/* -*- mode: C -*- */", file=out)
generate_digit_update(digit, out)
def generate_register(out):
print(
f"""\
/* -*- mode: C -*- */
#include "{FILE_PREFIX}_prologue.h"
#pragma GCC diagnostic push
#ifndef __clang__
# pragma GCC diagnostic ignored "-Wold-style-declaration"
#endif
}} static const __attribute__((__unused__)) {IMPL}_NEXT;
#pragma GCC diagnostic pop
_Static_assert(__builtin_types_compatible_p(void, \\
__typeof__({NS}_SEARCH({IMPL}_NEXT))), \\
"Only one singleton may be associated with each type.");
static __typeof__({IMPL}_NEXT) {IMPL}_NEXT = {{
""",
file=out,
)
generate_digit_update(0, out)
with open(f"{FILE_PREFIX}_register.inc", "w") as out:
generate_register(out)
struct foo {
int x;
#include "bridgetc_register.inc"
.x = 42,
};
struct bar {
double x;
#include "bridgetc_register.inc"
.x = 1.5,
};
int
test_foo()
{
struct {
__attribute__((packed)) struct foo tag[0];
char v;
} test;
return BTC_SEARCH(test.tag[0]).x;
}
# gcc -E -W -Wall -O test.c -o - | grep -v '^#' | clang-format-4.0
struct foo {
int x;
} static const __attribute__((__unused__)) BTC_value_000;
_Static_assert(__builtin_types_compatible_p(void, __typeof__((void)0)),
"Only one singleton may be associated with each type.");
static __typeof__(BTC_value_000) BTC_value_000 = {
.x = 42,
};
struct bar {
double x;
} static const __attribute__((__unused__)) BTC_value_001;
_Static_assert(__builtin_types_compatible_p(
void,
__typeof__(__builtin_choose_expr(
__builtin_types_compatible_p(__typeof__(BTC_value_001),
__typeof__(BTC_value_000)),
BTC_value_000, (void)0))),
"Only one singleton may be associated with each type.");
static __typeof__(BTC_value_001) BTC_value_001 = {
.x = 1.5,
};
int test_foo() {
struct {
__attribute__((packed)) struct foo tag[0];
char v;
} test;
return __builtin_choose_expr(
__builtin_types_compatible_p(__typeof__(test.tag[0]),
__typeof__(BTC_value_001)),
BTC_value_001,
__builtin_choose_expr(
__builtin_types_compatible_p(__typeof__(test.tag[0]),
__typeof__(BTC_value_000)),
BTC_value_000, (void)0))
.x;
}
.file "test.c"
.text
.globl test_foo
.type test_foo, @function
test_foo:
.LFB0:
.cfi_startproc
movl $42, %eax
ret
.cfi_endproc
.LFE0:
.size test_foo, .-test_foo
.ident "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
.section .note.GNU-stack,"",@progbits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment