Beautified from_str_vec

This commit is contained in:
Dr. Patrick Urbanke
2025-04-09 09:07:28 +02:00
parent 8a99272eca
commit f9340c99fd
3 changed files with 58 additions and 109 deletions

View File

@@ -1,21 +0,0 @@
#ifndef SQLGEN_INTERNAL_FROM_STR_HPP_
#define SQLGEN_INTERNAL_FROM_STR_HPP_
#include <optional>
#include <string>
#include <type_traits>
#include "../Result.hpp"
#include "../parsing/Parser.hpp"
namespace sqlgen::internal {
template <class T>
Result<T> from_str(const std::optional<std::string>& _str) {
using Type = std::remove_cvref_t<T>;
return Parser<Type>::read(_str);
}
} // namespace sqlgen::internal
#endif

View File

@@ -1,25 +1,79 @@
#ifndef SQLGEN_INTERNAL_FROM_STR_VEC_HPP_
#define SQLGEN_INTERNAL_FROM_STR_VEC_HPP_
#include <array>
#include <optional>
#include <rfl.hpp>
#include <sstream>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include "../Result.hpp"
#include "../parsing/ViewReader.hpp"
#include "../parsing/Parser.hpp"
namespace sqlgen::internal {
template <class ViewType, size_t i>
void assign_if_field_is_field_i(
const std::vector<std::optional<std::string>>& _row, const size_t _i,
ViewType* _view, std::optional<Error>* _err) noexcept {
using FieldType = rfl::tuple_element_t<i, typename ViewType::Fields>;
using OriginalType = typename FieldType::Type;
using T =
std::remove_cvref_t<std::remove_pointer_t<typename FieldType::Type>>;
constexpr auto name = FieldType::name();
if (_i == i) {
auto res = parsing::Parser<T>::read(_row[i]);
if (!res) {
std::stringstream stream;
stream << "Failed to parse field '" << std::string(name)
<< "': " << res.error().what();
*_err = Error(stream.str());
return;
}
rfl::get<i>(*_view) = std::move(*res);
}
}
template <class ViewType, size_t... is>
std::optional<Error> assign_to_field_i(
const std::vector<std::optional<std::string>>& _row, const size_t _i,
ViewType* _view, std::integer_sequence<size_t, is...>) noexcept {
std::optional<Error> err;
(assign_if_field_is_field_i<is>(_row, _i, _view, &err), ...);
return err;
}
template <class ViewType>
std::pair<std::optional<Error>, size_t> read_into_view(
const std::vector<std::optional<std::string>>& _row,
ViewType* _view) noexcept {
constexpr size_t size = ViewType::size();
if (_row.size() != size) {
std::stringstream stream;
stream << "Expected exactly " << std::to_string(size) << " fields, but got "
<< _row.size() << ".";
return std::make_pair(Error(stream.str()), 0);
}
for (size_t i = 0; i < size; ++i) {
const auto err = assign_to_field_i(
_row, i, _view, std::make_integer_sequence<size_t, size>());
if (err) {
return std::make_pair(err, i);
}
}
return std::make_pair(std::nullopt, size);
}
template <class T>
Result<T> from_str_vec(
const std::vector<std::optional<std::string>>& _str_vec) {
T t;
auto view = rfl::to_view(t);
auto view_reader =
parsing::ViewReader<std::remove_cvref_t<decltype(view)>>(&view);
const auto [err, num_fields_assigned] = view_reader.read(_str_vec);
const auto [err, num_fields_assigned] = read_into_view(_str_vec, &view);
if (err) {
return error(err->what());
}

View File

@@ -1,84 +0,0 @@
#ifndef SQLGEN_PARSING_VIEWREADER_HPP_
#define SQLGEN_PARSING_VIEWREADER_HPP_
#include <array>
#include <optional>
#include <rfl.hpp>
#include <sstream>
#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
#include "../Result.hpp"
#include "Parser.hpp"
namespace sqlgen::parsing {
template <class ViewType>
class ViewReader {
private:
static constexpr size_t size_ = ViewType::size();
public:
ViewReader(ViewType* _view) : view_(_view) {}
~ViewReader() = default;
std::pair<std::optional<Error>, size_t> read(
const std::vector<std::optional<std::string>>& _row) noexcept {
if (_row.size() != size_) {
std::stringstream stream;
stream << "Expected exactly " << std::to_string(size_)
<< " fields, but got " << _row.size() << ".";
return std::make_pair(Error(stream.str()), 0);
}
for (size_t i = 0; i < size_; ++i) {
const auto err = assign_to_field_i(
_row, i, &view_, std::make_integer_sequence<size_t, size_>());
if (err) {
return std::make_pair(err, i);
}
}
return std::make_pair(std::nullopt, size_);
}
private:
template <size_t i>
static void assign_if_field_is_field_i(
const std::vector<std::optional<std::string>>& _row, const size_t _i,
ViewType* _view, std::optional<Error>* _err) noexcept {
using FieldType = rfl::tuple_element_t<i, typename ViewType::Fields>;
using OriginalType = typename FieldType::Type;
using T =
std::remove_cvref_t<std::remove_pointer_t<typename FieldType::Type>>;
constexpr auto name = FieldType::name();
if (_i == i) {
auto res = Parser<T>::read(_row[i]);
if (!res) {
std::stringstream stream;
stream << "Failed to parse field '" << std::string(name)
<< "': " << res.error().what();
*_err = Error(stream.str());
return;
}
rfl::get<i>(*_view) = std::move(*res);
}
}
template <size_t... is>
static std::optional<Error> assign_to_field_i(
const std::vector<std::optional<std::string>>& _row, const size_t _i,
ViewType* _view, std::integer_sequence<size_t, is...>) noexcept {
std::optional<Error> err;
(assign_if_field_is_field_i<is>(_row, _i, _view, &err), ...);
return err;
}
private:
ViewType* view_;
};
} // namespace sqlgen::parsing
#endif