How to call a C++ function with std::uint64_t as its parameter?

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! :slight_smile:

================================================
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

Terms of Service

Privacy Policy

Cookie Policy