Edit:
I think the XXX-Bridging-Header.c
can only have C code. The C++ <cstdint>
can be replaced with C <stdint.h>
and the C++ std::uint64_t
be C uint64_t
.
count_digit.hpp:
#ifndef count_digit_hpp
#define count_digit_hpp
#include <stdint.h>
// I only need to support Swift Int
extern "C" int64_t count_digit(int64_t m);
#endif /* count_digit_hpp */
count_digit.cpp:
#include "count_digit.hpp"
#include <cassert>
//#include <cstdint>
#include <cstddef>
constexpr int floor_log10_pow2(int e) noexcept {
return (e * 1262611) >> 22;
}
constexpr int ceil_log10_pow2(int e) noexcept {
return e == 0 ? 0 : floor_log10_pow2(e) + 1;
}
struct digit_count_table_holder_t {
uint64_t entry[64];
};
constexpr digit_count_table_holder_t generate_digit_count_table() {
digit_count_table_holder_t table{ {} };
constexpr uint64_t pow10[] = {
1ull,
10ull,
100ull,
1000ull,
1'0000ull,
10'0000ull,
100'0000ull,
1000'0000ull,
1'0000'0000ull,
10'0000'0000ull,
100'0000'0000ull,
1000'0000'0000ull,
1'0000'0000'0000ull,
10'0000'0000'0000ull,
100'0000'0000'0000ull,
1000'0000'0000'0000ull,
1'0000'0000'0000'0000ull,
10'0000'0000'0000'0000ull,
100'0000'0000'0000'0000ull,
1000'0000'0000'0000'0000ull
};
for (int i = 0; i < 64; ++i) {
auto const ub = uint64_t(ceil_log10_pow2(i));
assert(ub <= 19);
table.entry[i] = ((ub + 1) << 52) - (pow10[ub] >> (i / 4));
}
return table;
}
// `inline`: warning: Inline variables are a C++17 extension
// fix this warning by changing C++ dialect to C++17 in project built settings
constexpr inline auto digit_count_table = generate_digit_count_table();
int floor_log2(uint64_t n) noexcept {
return 63 ^ __builtin_clzll(n);
}
// this is the function I want to call, it's now pure C
int64_t count_digit(int64_t m) {
uint64_t n = (uint64_t) m;
return int((digit_count_table.entry[floor_log2(n)] + (n >> (floor_log2(n) / 4))) >> 52);
}
Bridging-Header.c:
#include "stdint.h"
int64_t count_digit(int64_t m);
Swift:
extension Int {
var digits: Int {
Int(count_digit(Int64(self)))
}
}
this works!
================================================
Original post:
I want to call a simple function in C++, all it's a standalone function that uses C++ type std::uint64_t
for its one parameter. Due to this C++ type parameter, there is no way to make this function "pure C"?
In my iOS project, I'm able to add this .cpp
and .hpp
, however, when I #include
the .hpp
in `XXX-Bridging-Header.h", I get this:
'cstdint' file not found
so it appears the problem is the bridging header can only be plain "C"? Is there anyway to bridge to C++?
count_digit.hpp:
#ifndef count_digit_hpp
#define count_digit_hpp
#include <stdio.h>
#include <cstdint>
// is there anyway to make this a pure C function so this can be #included in the bridging header?
// or make the bridging understand C++
extern "C" int count_digit(std::uint64_t n) noexcept;
#endif /* count_digit_hpp */
count_digit.cpp:
#include "count_digit.hpp"
#include <cassert>
#include <cstdint>
#include <cstddef>
constexpr int floor_log10_pow2(int e) noexcept {
return (e * 1262611) >> 22;
}
constexpr int ceil_log10_pow2(int e) noexcept {
return e == 0 ? 0 : floor_log10_pow2(e) + 1;
}
struct digit_count_table_holder_t {
std::uint64_t entry[64];
};
constexpr digit_count_table_holder_t generate_digit_count_table() {
digit_count_table_holder_t table{ {} };
constexpr std::uint64_t pow10[] = {
1ull,
10ull,
100ull,
1000ull,
1'0000ull,
10'0000ull,
100'0000ull,
1000'0000ull,
1'0000'0000ull,
10'0000'0000ull,
100'0000'0000ull,
1000'0000'0000ull,
1'0000'0000'0000ull,
10'0000'0000'0000ull,
100'0000'0000'0000ull,
1000'0000'0000'0000ull,
1'0000'0000'0000'0000ull,
10'0000'0000'0000'0000ull,
100'0000'0000'0000'0000ull,
1000'0000'0000'0000'0000ull
};
for (int i = 0; i < 64; ++i) {
auto const ub = std::uint64_t(ceil_log10_pow2(i));
assert(ub <= 19);
table.entry[i] = ((ub + 1) << 52) - (pow10[ub] >> (i / 4));
}
return table;
}
// `inline`: warning: Inline variables are a C++17 extension
// wrong C++ version? How to set C++ version to allow `inline` without warning?
constexpr inline auto digit_count_table = generate_digit_count_table();
int floor_log2(std::uint64_t n) noexcept {
return 63 ^ __builtin_clzll(n);
}
// this is the function I want to call
int count_digit(std::uint64_t n) noexcept {
return int((digit_count_table.entry[floor_log2(n)] + (n >> (floor_log2(n) / 4))) >> 52);
}
this is a continuation of my quest to get a fast "count digit of an Int": Help me with maximizing performance of some code translated from C to Swift
this one does 64bit unsigned instead of 32bit..I want this for used with Swift Int which is 64bit