13#if !defined(ULTRA_COLUMNS_INFO_H)
14# error "Don't include this file directly, include the specific .h instead"
17#if !defined(ULTRA_COLUMNS_INFO_TCC)
18#define ULTRA_COLUMNS_INFO_TCC
23[[nodiscard]]
constexpr std::size_t normalised_column_count(
24 std::size_t raw_count, std::optional<std::size_t> output_index)
noexcept
26 return raw_count + (output_index ? 0 : 1);
29[[nodiscard]]
constexpr std::optional<std::size_t> raw_column_index(
30 std::size_t idx, std::optional<std::size_t> output_index)
noexcept
33 return idx == 0 ? std::nullopt : std::optional<std::size_t>(idx - 1);
38 return idx <= *output_index ? idx - 1 : idx;
41template<DataframeRow R>
42class normalised_row_view
45 using value_type = std::ranges::range_value_t<R>;
47 normalised_row_view(
const R &r, std::optional<std::size_t> output_index)
48 : r_(&r), output_index_(output_index),
49 logical_size_(normalised_column_count(std::ranges::size(r), output_index))
51 Expects(!output_index_ || *output_index_ < std::ranges::size(r));
54 [[nodiscard]] std::size_t size() const noexcept {
return logical_size_; }
59 using difference_type = std::ptrdiff_t;
60 using value_type = normalised_row_view::value_type;
61 using iterator_concept = std::forward_iterator_tag;
62 using iterator_category = std::forward_iterator_tag;
66 iterator(
const normalised_row_view *view, std::size_t pos)
67 : view_(view), pos_(pos)
73 it_ = std::ranges::begin(*view_->r_);
74 std::advance(it_, *raw_idx_);
78 [[nodiscard]]
const value_type &operator*()
const
86 iterator &operator++()
88 const auto previous_raw_idx(raw_idx_);
92 if (pos_ >= view_->logical_size_)
103 if (previous_raw_idx && *raw_idx_ == *previous_raw_idx + 1)
107 it_ = std::ranges::begin(*view_->r_);
108 std::advance(it_, *raw_idx_);
114 iterator operator++(
int)
121 [[nodiscard]]
bool operator==(
const iterator &other)
const noexcept
123 return view_ == other.view_ && pos_ == other.pos_;
127 void refresh_raw_index()
129 raw_idx_ = pos_ < view_->logical_size_
130 ? view_->raw_column(pos_)
134 const normalised_row_view *view_ {};
136 std::optional<std::size_t> raw_idx_ {};
137 std::ranges::iterator_t<const R> it_ {};
140 [[nodiscard]] iterator begin()
const {
return iterator(
this, 0); }
141 [[nodiscard]] iterator end()
const {
return iterator(
this, logical_size_); }
144 [[nodiscard]] std::optional<std::size_t> raw_column(
145 std::size_t pos)
const noexcept
147 return raw_column_index(pos, output_index_);
151 std::optional<std::size_t> output_index_;
152 std::size_t logical_size_;
153 const value_type empty_ {};
183template<DataframeMatrix R>
186 using VT = std::ranges::range_value_t<std::ranges::range_value_t<R>>;
188 Expects(!std::ranges::empty(exs));
189 Expects(std::ranges::size(*std::ranges::begin(exs)));
192 const internal::normalised_row_view header_row(*std::ranges::begin(exs),
196 cols_.reserve(header_row.size());
198 for (
const auto &name : header_row)
199 if constexpr (std::same_as<VT, std::string>)
200 cols_.emplace_back(*
this, trim(name));
202 cols_.emplace_back(*
this, trim(lexical_cast<std::string>(name)));
204 const auto update_domain([
this](std::size_t idx,
const auto &value)
206 if constexpr (std::same_as<VT, std::string>)
208 if (trim(value).empty())
217 switch (cols_[idx].domain())
220 if constexpr (std::same_as<VT, std::string>)
222 if (is_integer(value))
223 cols_[idx].domain(d_int);
224 else if (is_number(value))
225 cols_[idx].domain(d_double);
227 cols_[idx].domain(d_string);
232 cols_[idx].domain(
static_cast<domain_t>(value.index()));
237 if constexpr (std::same_as<VT, std::string>)
239 if (is_integer(value))
244 if (value.index() == d_int)
248 cols_[idx].domain(d_double);
252 if constexpr (std::same_as<VT, std::string>)
254 if (is_number(value))
265 if constexpr (std::same_as<VT, std::string>)
266 cols_[idx].domain(d_string);
267 else if (value.index() == d_string)
268 cols_[idx].domain(d_string);
273 constexpr std::size_t max_domain_samples(1000);
277 std::vector<std::ranges::range_value_t<R>> sample_rows;
278 sample_rows.reserve(max_domain_samples);
280 std::minstd_rand rng(0);
281 std::size_t valid_rows(0);
283 for (
const auto &row : exs | std::views::drop(1))
286 && *output_index >=
static_cast<std::size_t
>(std::ranges::distance(row)))
289 if (
const internal::normalised_row_view normalised(row, output_index);
290 normalised.size() !=
size())
295 if (sample_rows.size() < max_domain_samples)
296 sample_rows.push_back(row);
299 std::uniform_int_distribution<std::size_t> dist(0, valid_rows - 1);
301 if (
const auto idx(dist(rng)); idx < max_domain_samples)
302 sample_rows[idx] = row;
306 for (
const auto &row : sample_rows)
308 const internal::normalised_row_view normalised(row, output_index);
310 for (std::size_t idx(0);
const auto &value : normalised)
312 update_domain(idx, value);
size_type size() const noexcept
Definition columns_info.cc:264
void build(const R &, std::optional< std::size_t >)
Definition columns_info.h:185
bool basic_data_type(domain_t d) noexcept
Definition value.cc:40
bool has_value(const value_t &v) noexcept
Definition value.cc:31
bool numerical_data_type(domain_t d) noexcept
Definition value.cc:65
domain_t
Definition value.h:38