Skip to content

Commit

Permalink
Added SnakeCaseToHungarianCase
Browse files Browse the repository at this point in the history
  • Loading branch information
Patrick Urbanke committed Apr 28, 2024
1 parent 3bdca9b commit 54061a3
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 36 deletions.
1 change: 1 addition & 0 deletions include/rfl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "rfl/Rename.hpp"
#include "rfl/Size.hpp"
#include "rfl/SnakeCaseToCamelCase.hpp"
#include "rfl/SnakeCaseToHungarianCase.hpp"
#include "rfl/TaggedUnion.hpp"
#include "rfl/Timestamp.hpp"
#include "rfl/Validator.hpp"
Expand Down
44 changes: 8 additions & 36 deletions include/rfl/SnakeCaseToCamelCase.hpp
Original file line number Diff line number Diff line change
@@ -1,57 +1,29 @@
#ifndef RFL_SNAKECASETOCAMELCASE_HPP_
#define RFL_SNAKECASETOCAMELCASE_HPP_

#include <array>
#include <string_view>

#include "Field.hpp"
#include "internal/StringLiteral.hpp"
#include "internal/transform_snake_case.hpp"

namespace rfl {
namespace internal {
/// Capitalizes a lower-case character.
template <char c>
consteval char to_upper() {
if constexpr (c >= 'a' && c <= 'z') {
return c + ('A' - 'a');
} else {
return c;
}
}

/// Transforms the field name from snake case to camel case.
template <internal::StringLiteral _name, bool _capitalize, size_t _i = 0,
char... chars>
consteval auto transform_field_name() {
if constexpr (_i == _name.arr_.size()) {
return StringLiteral<sizeof...(chars) + 1>(chars...);
} else if constexpr (_name.arr_[_i] == '_') {
return transform_field_name<_name, true, _i + 1, chars...>();
} else if constexpr (_capitalize) {
return transform_field_name<_name, false, _i + 1, chars...,
to_upper<_name.arr_[_i]>()>();
} else {
return transform_field_name<_name, false, _i + 1, chars...,
_name.arr_[_i]>();
}
}
} // namespace internal

struct SnakeCaseToCamelCase {
public:
/// Replaces all instances of snake_case field names with CamelCase.
template <class StructType>
static auto process(auto _named_tuple) {
const auto handle_one = [](const auto& _f) { return handle_one_field(_f); };
static auto process(auto&& _named_tuple) {
const auto handle_one = [](auto&& _f) {
return handle_one_field(std::move(_f));
};
return _named_tuple.transform(handle_one);
}

private:
/// Applies the logic to a single field.
template <class FieldType>
static auto handle_one_field(const FieldType& _f) {
static auto handle_one_field(FieldType&& _f) {
using NewFieldType =
Field<internal::transform_field_name<FieldType::name_, true>(),
Field<internal::transform_snake_case<FieldType::name_,
/*capitalize=*/true>(),
typename FieldType::Type>;
return NewFieldType(_f.value());
}
Expand Down
34 changes: 34 additions & 0 deletions include/rfl/SnakeCaseToHungarianCase.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef RFL_SNAKECASETOHUNGARIANCASE_HPP_
#define RFL_SNAKECASETOHUNGARIANCASE_HPP_

#include "Field.hpp"
#include "internal/transform_snake_case.hpp"

namespace rfl {

struct SnakeCaseToHungarianCase {
public:
/// Replaces all instances of snake_case field names with CamelCase.
template <class StructType>
static auto process(auto&& _named_tuple) {
const auto handle_one = [](auto&& _f) {
return handle_one_field(std::move(_f));
};
return _named_tuple.transform(handle_one);
}

private:
/// Applies the logic to a single field.
template <class FieldType>
static auto handle_one_field(FieldType&& _f) {
using NewFieldType =
Field<internal::transform_snake_case<FieldType::name_,
/*capitalize=*/false>(),
typename FieldType::Type>;
return NewFieldType(_f.value());
}
};

} // namespace rfl

#endif
36 changes: 36 additions & 0 deletions include/rfl/internal/transform_snake_case.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef RFL_INTERNAL_TRANSFORMSNAKECASE_HPP_
#define RFL_INTERNAL_TRANSFORMSNAKECASE_HPP_

#include "StringLiteral.hpp"

namespace rfl::internal {

/// Capitalizes a lower-case character.
template <char c>
consteval char to_upper() {
if constexpr (c >= 'a' && c <= 'z') {
return c + ('A' - 'a');
} else {
return c;
}
}

/// Transforms the field name from snake case to camel case.
template <internal::StringLiteral _name, bool _capitalize, size_t _i = 0,
char... chars>
consteval auto transform_snake_case() {
if constexpr (_i == _name.arr_.size()) {
return StringLiteral<sizeof...(chars) + 1>(chars...);
} else if constexpr (_name.arr_[_i] == '_') {
return transform_snake_case<_name, true, _i + 1, chars...>();
} else if constexpr (_capitalize) {
return transform_snake_case<_name, false, _i + 1, chars...,
to_upper<_name.arr_[_i]>()>();
} else {
return transform_snake_case<_name, false, _i + 1, chars...,
_name.arr_[_i]>();
}
}
} // namespace rfl::internal

#endif
40 changes: 40 additions & 0 deletions tests/json/test_snake_case_to_hungarian_case.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <iostream>
#include <rfl.hpp>
#include <rfl/json.hpp>
#include <source_location>
#include <string>
#include <vector>

#include "write_and_read.hpp"

namespace test_snake_case_to_hungarian_case {

struct Person {
std::string first_name;
std::string last_name;
rfl::Timestamp<"%Y-%m-%d"> birthday;
std::vector<Person> children;
};

TEST(json, test_snake_case_to_hungarian_case) {
const auto bart = Person{
.first_name = "Bart", .last_name = "Simpson", .birthday = "1987-04-19"};

const auto lisa = Person{
.first_name = "Lisa", .last_name = "Simpson", .birthday = "1987-04-19"};

const auto maggie = Person{
.first_name = "Maggie", .last_name = "Simpson", .birthday = "1987-04-19"};

const auto homer =
Person{.first_name = "Homer",
.last_name = "Simpson",
.birthday = "1987-04-19",
.children = std::vector<Person>({bart, lisa, maggie})};

const auto named_tuple =
rfl::to_named_tuple<rfl::SnakeCaseToHungarianCase>(homer);

std::cout << rfl::json::write(named_tuple, rfl::json::pretty) << std::endl;
}
} // namespace test_snake_case_to_hungarian_case

0 comments on commit 54061a3

Please sign in to comment.