#pragma once #include "column.h" #include "utils.h" #include namespace clickhouse { /** * Represents column of Tuple([T]). */ class ColumnTuple : public Column { public: ColumnTuple(const std::vector& columns); /// Returns count of columns in the tuple. size_t TupleSize() const; inline ColumnRef operator [] (size_t n) const { return columns_[n]; } inline ColumnRef At(size_t n) const { return columns_[n]; } public: /// Increase the capacity of the column for large block insertion. void Reserve(size_t new_cap) override; /// Appends content of given column to the end of current one. void Append(ColumnRef column) override; /// Loads column prefix from input stream. bool LoadPrefix(InputStream* input, size_t rows) override; /// Loads column data from input stream. bool LoadBody(InputStream* input, size_t rows) override; /// Saves column prefix to output stream. void SavePrefix(OutputStream* output) override; /// Saves column data to output stream. void SaveBody(OutputStream* output) override; /// Clear column data . void Clear() override; /// Returns count of rows in the column. size_t Size() const override; /// Makes slice of the current column. ColumnRef Slice(size_t, size_t) const override; ColumnRef CloneEmpty() const override; void Swap(Column& other) override; private: std::vector columns_; }; template class ColumnTupleT : public ColumnTuple { public: using TupleOfColumns = std::tuple...>; using ValueType = std::tuple().At(0))>...>; ColumnTupleT(std::tuple...> columns) : ColumnTuple(TupleToVector(columns)), typed_columns_(std::move(columns)) {} ColumnTupleT(std::vector columns) : ColumnTuple(columns), typed_columns_(VectorToTuple(std::move(columns))) {} ColumnTupleT(const std::initializer_list columns) : ColumnTuple(columns), typed_columns_(VectorToTuple(std::move(columns))) {} inline ValueType At(size_t index) const { return GetTupleOfValues(index); } inline ValueType operator[](size_t index) const { return GetTupleOfValues(index); } using ColumnTuple::Append; template inline void Append(std::tuple value) { AppendTuple(std::move(value)); } /** Create a ColumnTupleT from a ColumnTuple, without copying data and offsets, but by * 'stealing' those from `col`. * * Ownership of column internals is transferred to returned object, original (argument) object * MUST NOT BE USED IN ANY WAY, it is only safe to dispose it. * * Throws an exception if `col` is of wrong type, it is safe to use original col in this case. * This is a static method to make such conversion verbose. */ static auto Wrap(ColumnTuple&& col) { if (col.TupleSize() != std::tuple_size_v) { throw ValidationError("Can't wrap from " + col.GetType().GetName()); } return std::make_shared>(VectorToTuple(std::move(col))); } static auto Wrap(Column&& col) { return Wrap(std::move(dynamic_cast(col))); } // Helper to simplify integration with other APIs static auto Wrap(ColumnRef&& col) { return Wrap(std::move(*col->AsStrict())); } ColumnRef Slice(size_t begin, size_t size) const override { return Wrap(ColumnTuple::Slice(begin, size)); } ColumnRef CloneEmpty() const override { return Wrap(ColumnTuple::CloneEmpty()); } void Swap(Column& other) override { auto& col = dynamic_cast&>(other); typed_columns_.swap(col.typed_columns_); ColumnTuple::Swap(other); } private: template > inline void AppendTuple([[maybe_unused]] T value) { static_assert(index <= std::tuple_size_v); static_assert(std::tuple_size_v == std::tuple_size_v); if constexpr (index == 0) { return; } else { std::get(typed_columns_)->Append(std::move(std::get(value))); AppendTuple(std::move(value)); } } template > inline static std::vector TupleToVector([[maybe_unused]] const T& value) { static_assert(index <= std::tuple_size_v); if constexpr (index == 0) { std::vector result; result.reserve(std::tuple_size_v); return result; } else { auto result = TupleToVector(value); result.push_back(std::get(value)); return result; } } template > inline static auto VectorToTuple([[maybe_unused]] T columns) { static_assert(column_index <= std::tuple_size_v); if constexpr (column_index == 0) { return std::make_tuple(); } else { using ColumnType = typename std::tuple_element::type::element_type; auto column = WrapColumn(columns[column_index - 1]); return std::tuple_cat(std::move(VectorToTuple(std::move(columns))), std::make_tuple(std::move(column))); } } template > inline auto GetTupleOfValues([[maybe_unused]]size_t index) const { static_assert(column_index <= std::tuple_size_v); if constexpr (column_index == 0) { return std::make_tuple(); } else { return std::tuple_cat( std::move(GetTupleOfValues(index)), std::move(std::make_tuple(std::get(typed_columns_)->At(index)))); } } TupleOfColumns typed_columns_; }; } // namespace clickhouse