Skip to content

Instantly share code, notes, and snippets.

@battleguard
Last active October 24, 2023 15:45
Show Gist options
  • Save battleguard/3197197d891c18c7ad251d6a745a1046 to your computer and use it in GitHub Desktop.
Save battleguard/3197197d891c18c7ad251d6a745a1046 to your computer and use it in GitHub Desktop.
compile time conversion of global strings to snake case
#include <iostream>
#include <string>
#include <string_view>
#include "WsfPythonNaming.hpp"
void Foo()
{
}
template <typename Func>
void def(const char* name_, Func&& f)
{
std::cout << "def name= \"" << name_ << "\"\n";
}
constexpr bool strings_equal(char const* a, char const* b)
{
return std::string_view(a) == b;
}
constexpr bool strings_equal(std::string_view a, char const* b)
{
return std::string_view(a) == b;
}
int main()
{
using namespace wsf::python;
def("FooBarFooBar_FOO_BAR_FooFooFoo"_pyfunc, &Foo);
def("GetID"_pyfunc, &Foo);
def("GetId"_pyfunc, &Foo);
def("GetId_WSF"_pyfunc, &Foo);
def(PyFuncName("FooBarFooBar_FOO_BAR_FooFooFoo"), &Foo);
def(PyFuncName("GetID"), &Foo);
def(PyFuncName("GetId"), &Foo);
def(PyFuncName("GetId_WSF"), &Foo);
std::string comp = "Sensor";
def(PyFuncName("Get" + comp), &Foo);
def("WsfStringId"_pyclass, &Foo);
def("UtStringId"_pyclass, &Foo);
def("StringId"_pyclass, &Foo);
def(PyClassName("WsfStringId"), &Foo);
def(PyClassName("UtStringId"), &Foo);
def(PyClassName("StringId"), &Foo);
def(PyClassName(("Wsf" + comp).c_str()), &Foo);
static_assert(strings_equal("UtStringId"_pyclass, "StringId"), "class");
def("cENUM_NAME"_pyenum, &Foo);
def("cDEFAULT"_pyenum, &Foo);
def("FOO_ENUM"_pyenum, &Foo);
static_assert(strings_equal("cENUM_NAME"_pyenum, "ENUM_NAME"), "enum");
def(PyEnumName("cENUM_NAME"), &Foo);
def(PyEnumName("cDEFAULT"), &Foo);
def(PyEnumName("FOO_ENUM"), &Foo);
def(PyEnumName(("cENUM_" + comp).c_str()), &Foo);
static_assert(strings_equal("GetID_Foo"_pyfunc, "get_id_foo"), "strings are equal");
// static_assert(strings_equal("abc"_x2, "abcabc"), "strings are equal");
}
#pragma once
#include <string>
#include <string_view>
namespace wsf::python
{
namespace details
{
constexpr char charToLower(const char c)
{
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
}
// see DoubleString example from https://en.cppreference.com/w/cpp/language/user_literal
template <std::size_t N>
struct SnakeCaseConstCharArr
{
char result[N + N - 1]{};
constexpr SnakeCaseConstCharArr(char const (&aInputCharArray)[N])
{
size_t idx = 0;
bool prevCharUpper = true;
for (std::size_t i = 0; i < N; i++)
{
char curChar = aInputCharArray[i];
const bool isCurCharUpper = curChar >= 'A' && curChar <= 'Z';
if (isCurCharUpper)
{
// handle GetID_Foo -> get_id_foo instead of get_i_d__foo
if (!prevCharUpper && result[idx - 1] != '_')
{
result[idx++] = '_';
}
curChar = charToLower(curChar);
}
prevCharUpper = isCurCharUpper;
result[idx++] = curChar;
}
result[idx] = '\0';
}
};
}
inline const char* PyFuncName(std::string_view aData)
{
static std::string result;
result.clear();
bool prevCharUpper = true;
for (char curChar : aData)
{
const bool isCurCharUpper = curChar >= 'A' && curChar <= 'Z';
if (isCurCharUpper)
{
// handle GetID_Foo -> get_id_foo instead of get_i_d__foo
if (!prevCharUpper && result.back() != '_')
{
result += '_';
}
curChar = details::charToLower(curChar);
}
prevCharUpper = isCurCharUpper;
result += curChar;
}
return result.c_str();
}
constexpr const char* PyClassName(const char* input)
{
const auto sv = std::string_view(input);
for (const std::string_view prefix : { "Wsf", "Ut" })
{
if (sv.starts_with(prefix))
{
return input + prefix.length();
}
}
return input;
}
constexpr const char* PyEnumName(const char* aName)
{
if (aName[0] == 'c')
{
return aName + 1;
}
return aName;
}
constexpr const char* PyConstantName(const char* aName)
{
return PyEnumName(aName);
}
template <details::SnakeCaseConstCharArr A>
constexpr const char* operator""_pyfunc()
{
return A.result;
}
constexpr const char* operator""_pyclass(const char* input, std::size_t N)
{
return PyClassName(input);
}
constexpr const char* operator""_pyenum(const char* input, std::size_t N)
{
return PyEnumName(input);
}
constexpr const char* operator""_pyconst(const char* input, std::size_t N)
{
return PyConstantName(input);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment