File: VectorParser.hpp

package info (click to toggle)
reflect-cpp 0.21.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,128 kB
  • sloc: cpp: 50,336; python: 139; makefile: 30; sh: 3
file content (130 lines) | stat: -rw-r--r-- 4,326 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#ifndef RFL_PARSING_VECTORPARSER_HPP_
#define RFL_PARSING_VECTORPARSER_HPP_

#include <iterator>
#include <map>
#include <stdexcept>
#include <string>
#include <type_traits>

#include "../Bytestring.hpp"
#include "../Result.hpp"
#include "../Vectorstring.hpp"
#include "../always_false.hpp"
#include "MapParser.hpp"
#include "Parent.hpp"
#include "Parser_base.hpp"
#include "VectorReader.hpp"
#include "is_forward_list.hpp"
#include "is_map_like.hpp"
#include "is_map_like_not_multimap.hpp"
#include "is_set_like.hpp"
#include "schema/Type.hpp"

namespace rfl {
namespace parsing {

/// This can be used for data structures that would be expressed as array in
/// serialized format (std::vector, std::set, std::deque, ...),
/// but also includes map-like types, when the key is not of type
/// std::string.
template <class R, class W, class VecType, class ProcessorsType>
  requires AreReaderAndWriter<R, W, VecType>
struct VectorParser {
 public:
  using InputArrayType = typename R::InputArrayType;
  using InputVarType = typename R::InputVarType;

  using ParentType = Parent<W>;

  using T = typename VecType::value_type;

  static_assert(!std::is_same_v<std::remove_cvref_t<VecType>, Bytestring>,
                "Cannot be a bytestring.");
  static_assert(!std::is_same_v<std::remove_cvref_t<VecType>, Vectorstring>,
                "Cannot be a vectorstring.");

  static Result<VecType> read(const R& _r, const InputVarType& _var) noexcept {
    if constexpr (treat_as_map()) {
      return MapParser<R, W, VecType, ProcessorsType>::read(_r, _var);
    } else if constexpr (is_forward_list<VecType>()) {
      const auto to_forward_list = [](auto&& vec) -> std::forward_list<T> {
        std::forward_list<T> list;
        for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
          list.emplace_front(std::move(*it));
        }
        return list;
      };
      return Parser<R, W, std::vector<T>, ProcessorsType>::read(_r, _var)
          .transform(to_forward_list);
    } else {
      const auto parse = [&](const InputArrayType& _arr) -> Result<VecType> {
        VecType vec;
        auto vector_reader =
            VectorReader<R, W, VecType, ProcessorsType>(&_r, &vec);
        const auto err = _r.read_array(vector_reader, _arr);
        if (err) {
          return error(*err);
        }
        return vec;
      };
      return _r.to_array(_var).and_then(parse);
    }
  }

  template <class P>
  static void write(const W& _w, const VecType& _vec,
                    const P& _parent) noexcept {
    if constexpr (treat_as_map()) {
      MapParser<R, W, VecType, ProcessorsType>::write(_w, _vec, _parent);
    } else {
      auto arr = ParentType::add_array(
          _w, std::distance(_vec.begin(), _vec.end()), _parent);
      const auto new_parent = typename ParentType::Array{&arr};
      for (const auto& v : _vec) {
        Parser<R, W, std::remove_cvref_t<T>, ProcessorsType>::write(_w, v,
                                                                    new_parent);
      }
      _w.end_array(&arr);
    }
  }

  /// Generates a schema for the underlying type.
  static schema::Type to_schema(
      std::map<std::string, schema::Type>* _definitions) {
    if constexpr (treat_as_map()) {
      return MapParser<R, W, VecType, ProcessorsType>::to_schema(_definitions);
    } else {
      using Type = schema::Type;
      return Type{Type::TypedArray{
          .type_ = Ref<Type>::make(
              Parser<R, W, T, ProcessorsType>::to_schema(_definitions))}};
    }
  }

 private:
  static constexpr bool treat_as_map() {
    if constexpr (is_map_like_not_multimap<VecType>()) {
      if constexpr (internal::has_reflection_type_v<typename T::first_type>) {
        using U = std::remove_cvref_t<typename T::first_type::ReflectionType>;
        return std::is_same<U, std::string>() || std::is_integral_v<U> ||
               std::is_floating_point_v<U>;

        // We do not need std::string here, it is already caught by the template
        // specialization.
      } else if constexpr (std::is_integral_v<typename T::first_type> ||
                           std::is_floating_point_v<typename T::first_type>) {
        return true;
      } else {
        return false;
      }
    } else {
      return false;
    }
  }
};

}  // namespace parsing
}  // namespace rfl

#endif