2017-07-06 13:54:55 +00:00
|
|
|
#include <Columns/ColumnFixedString.h>
|
2018-04-23 16:40:25 +00:00
|
|
|
#include <Columns/ColumnsCommon.h>
|
2017-07-06 13:54:55 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/Arena.h>
|
|
|
|
#include <Common/SipHash.h>
|
|
|
|
#include <Common/memcpySmall.h>
|
2019-03-03 20:08:39 +00:00
|
|
|
#include <Common/memcmpSmall.h>
|
2019-08-21 02:28:04 +00:00
|
|
|
#include <Common/assert_cast.h>
|
2020-03-18 16:03:55 +00:00
|
|
|
#include <Common/WeakHash.h>
|
2020-03-18 16:18:37 +00:00
|
|
|
#include <Common/HashTable/Hash.h>
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-07-06 13:54:55 +00:00
|
|
|
#include <DataStreams/ColumnGathererStream.h>
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-07-06 13:54:55 +00:00
|
|
|
#include <IO/WriteHelpers.h>
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2019-01-04 12:10:00 +00:00
|
|
|
#ifdef __SSE2__
|
2017-04-01 07:20:54 +00:00
|
|
|
#include <emmintrin.h>
|
2017-03-11 04:41:28 +00:00
|
|
|
#endif
|
|
|
|
|
2017-03-11 00:38:30 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int TOO_LARGE_STRING_SIZE;
|
|
|
|
extern const int SIZE_OF_FIXED_STRING_DOESNT_MATCH;
|
|
|
|
extern const int SIZES_OF_COLUMNS_DOESNT_MATCH;
|
|
|
|
extern const int PARAMETER_OUT_OF_BOUND;
|
2020-03-19 17:35:08 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-14 03:56:56 +00:00
|
|
|
MutableColumnPtr ColumnFixedString::cloneResized(size_t size) const
|
2017-03-11 00:38:30 +00:00
|
|
|
{
|
2017-12-14 03:56:56 +00:00
|
|
|
MutableColumnPtr new_col_holder = ColumnFixedString::create(n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (size > 0)
|
|
|
|
{
|
2019-08-21 02:28:04 +00:00
|
|
|
auto & new_col = assert_cast<ColumnFixedString &>(*new_col_holder);
|
2017-04-01 07:20:54 +00:00
|
|
|
new_col.chars.resize(size * n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t count = std::min(this->size(), size);
|
2018-09-02 03:33:48 +00:00
|
|
|
memcpy(new_col.chars.data(), chars.data(), count * n * sizeof(chars[0]));
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (size > count)
|
|
|
|
memset(&(new_col.chars[count * n]), '\0', (size - count) * n);
|
|
|
|
}
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
return new_col_holder;
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ColumnFixedString::insert(const Field & x)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
const String & s = DB::get<const String &>(x);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (s.size() > n)
|
|
|
|
throw Exception("Too large string '" + s + "' for FixedString column", ErrorCodes::TOO_LARGE_STRING_SIZE);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t old_size = chars.size();
|
|
|
|
chars.resize_fill(old_size + n);
|
2019-03-07 20:04:59 +00:00
|
|
|
memcpy(chars.data() + old_size, s.data(), s.size());
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ColumnFixedString::insertFrom(const IColumn & src_, size_t index)
|
|
|
|
{
|
2019-08-21 02:28:04 +00:00
|
|
|
const ColumnFixedString & src = assert_cast<const ColumnFixedString &>(src_);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (n != src.getN())
|
|
|
|
throw Exception("Size of FixedString doesn't match", ErrorCodes::SIZE_OF_FIXED_STRING_DOESNT_MATCH);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t old_size = chars.size();
|
|
|
|
chars.resize(old_size + n);
|
2019-03-07 20:04:59 +00:00
|
|
|
memcpySmallAllowReadWriteOverflow15(chars.data() + old_size, &src.chars[n * index], n);
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ColumnFixedString::insertData(const char * pos, size_t length)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (length > n)
|
|
|
|
throw Exception("Too large string for FixedString column", ErrorCodes::TOO_LARGE_STRING_SIZE);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t old_size = chars.size();
|
|
|
|
chars.resize_fill(old_size + n);
|
2019-03-07 20:04:59 +00:00
|
|
|
memcpy(chars.data() + old_size, pos, length);
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef ColumnFixedString::serializeValueIntoArena(size_t index, Arena & arena, char const *& begin) const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
auto pos = arena.allocContinue(n, begin);
|
|
|
|
memcpy(pos, &chars[n * index], n);
|
|
|
|
return StringRef(pos, n);
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char * ColumnFixedString::deserializeAndInsertFromArena(const char * pos)
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t old_size = chars.size();
|
|
|
|
chars.resize(old_size + n);
|
2019-03-07 20:04:59 +00:00
|
|
|
memcpy(chars.data() + old_size, pos, n);
|
2017-04-01 07:20:54 +00:00
|
|
|
return pos + n;
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ColumnFixedString::updateHashWithValue(size_t index, SipHash & hash) const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
hash.update(reinterpret_cast<const char *>(&chars[n * index]), n);
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 16:03:55 +00:00
|
|
|
void ColumnFixedString::updateWeakHash32(WeakHash32 & hash) const
|
|
|
|
{
|
|
|
|
auto s = size();
|
|
|
|
|
|
|
|
if (hash.getData().size() != s)
|
|
|
|
throw Exception("Size of WeakHash32 does not match size of column: column size is " + std::to_string(s) +
|
|
|
|
", hash size is " + std::to_string(hash.getData().size()), ErrorCodes::LOGICAL_ERROR);
|
|
|
|
|
2020-03-25 11:14:11 +00:00
|
|
|
const UInt8 * pos = chars.data();
|
|
|
|
UInt32 * hash_data = hash.getData().data();
|
2020-03-18 16:03:55 +00:00
|
|
|
|
|
|
|
for (size_t row = 0; row < s; ++row)
|
|
|
|
{
|
2020-03-18 16:18:37 +00:00
|
|
|
*hash_data = ::updateWeakHash32(pos, n, *hash_data);
|
2020-03-18 16:03:55 +00:00
|
|
|
|
|
|
|
pos += n;
|
|
|
|
++hash_data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-11 00:38:30 +00:00
|
|
|
template <bool positive>
|
|
|
|
struct ColumnFixedString::less
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
const ColumnFixedString & parent;
|
2017-09-07 21:04:48 +00:00
|
|
|
explicit less(const ColumnFixedString & parent_) : parent(parent_) {}
|
2017-04-01 07:20:54 +00:00
|
|
|
bool operator()(size_t lhs, size_t rhs) const
|
|
|
|
{
|
2019-03-03 20:08:39 +00:00
|
|
|
int res = memcmpSmallAllowOverflow15(parent.chars.data() + lhs * parent.n, parent.chars.data() + rhs * parent.n, parent.n);
|
2017-04-01 07:20:54 +00:00
|
|
|
return positive ? (res < 0) : (res > 0);
|
|
|
|
}
|
2017-03-11 00:38:30 +00:00
|
|
|
};
|
|
|
|
|
2019-02-18 19:44:26 +00:00
|
|
|
void ColumnFixedString::getPermutation(bool reverse, size_t limit, int /*nan_direction_hint*/, Permutation & res) const
|
2017-03-11 00:38:30 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t s = size();
|
|
|
|
res.resize(s);
|
|
|
|
for (size_t i = 0; i < s; ++i)
|
|
|
|
res[i] = i;
|
|
|
|
|
|
|
|
if (limit >= s)
|
|
|
|
limit = 0;
|
|
|
|
|
|
|
|
if (limit)
|
|
|
|
{
|
|
|
|
if (reverse)
|
|
|
|
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less<false>(*this));
|
|
|
|
else
|
|
|
|
std::partial_sort(res.begin(), res.begin() + limit, res.end(), less<true>(*this));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (reverse)
|
|
|
|
std::sort(res.begin(), res.end(), less<false>(*this));
|
|
|
|
else
|
|
|
|
std::sort(res.begin(), res.end(), less<true>(*this));
|
|
|
|
}
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ColumnFixedString::insertRangeFrom(const IColumn & src, size_t start, size_t length)
|
|
|
|
{
|
2019-08-21 02:28:04 +00:00
|
|
|
const ColumnFixedString & src_concrete = assert_cast<const ColumnFixedString &>(src);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (start + length > src_concrete.size())
|
|
|
|
throw Exception("Parameters start = "
|
|
|
|
+ toString(start) + ", length = "
|
|
|
|
+ toString(length) + " are out of bound in ColumnFixedString::insertRangeFrom method"
|
|
|
|
" (size() = " + toString(src_concrete.size()) + ").",
|
|
|
|
ErrorCodes::PARAMETER_OUT_OF_BOUND);
|
|
|
|
|
|
|
|
size_t old_size = chars.size();
|
|
|
|
chars.resize(old_size + length * n);
|
2019-03-07 20:04:59 +00:00
|
|
|
memcpy(chars.data() + old_size, &src_concrete.chars[start * n], length * n);
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:17:09 +00:00
|
|
|
ColumnPtr ColumnFixedString::filter(const IColumn::Filter & filt, ssize_t result_size_hint) const
|
2017-03-11 00:38:30 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t col_size = size();
|
|
|
|
if (col_size != filt.size())
|
|
|
|
throw Exception("Size of filter doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-12-14 03:56:56 +00:00
|
|
|
auto res = ColumnFixedString::create(n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (result_size_hint)
|
|
|
|
res->chars.reserve(result_size_hint > 0 ? result_size_hint * n : chars.size());
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2018-09-02 03:00:04 +00:00
|
|
|
const UInt8 * filt_pos = filt.data();
|
2017-04-01 07:20:54 +00:00
|
|
|
const UInt8 * filt_end = filt_pos + col_size;
|
2018-09-02 03:00:04 +00:00
|
|
|
const UInt8 * data_pos = chars.data();
|
2017-03-11 04:41:28 +00:00
|
|
|
|
2019-01-04 12:10:00 +00:00
|
|
|
#ifdef __SSE2__
|
2017-04-01 07:20:54 +00:00
|
|
|
/** A slightly more optimized version.
|
|
|
|
* Based on the assumption that often pieces of consecutive values
|
|
|
|
* completely pass or do not pass the filter.
|
|
|
|
* Therefore, we will optimistically check the parts of `SIMD_BYTES` values.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static constexpr size_t SIMD_BYTES = 16;
|
|
|
|
const __m128i zero16 = _mm_setzero_si128();
|
|
|
|
const UInt8 * filt_end_sse = filt_pos + col_size / SIMD_BYTES * SIMD_BYTES;
|
|
|
|
const size_t chars_per_simd_elements = SIMD_BYTES * n;
|
|
|
|
|
|
|
|
while (filt_pos < filt_end_sse)
|
|
|
|
{
|
|
|
|
int mask = _mm_movemask_epi8(_mm_cmpgt_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(filt_pos)), zero16));
|
|
|
|
|
|
|
|
if (0 == mask)
|
|
|
|
{
|
|
|
|
/// Nothing is inserted.
|
|
|
|
data_pos += chars_per_simd_elements;
|
|
|
|
}
|
|
|
|
else if (0xFFFF == mask)
|
|
|
|
{
|
|
|
|
res->chars.insert(data_pos, data_pos + chars_per_simd_elements);
|
|
|
|
data_pos += chars_per_simd_elements;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-08 04:58:57 +00:00
|
|
|
size_t res_chars_size = res->chars.size();
|
2017-04-01 07:20:54 +00:00
|
|
|
for (size_t i = 0; i < SIMD_BYTES; ++i)
|
|
|
|
{
|
|
|
|
if (filt_pos[i])
|
|
|
|
{
|
|
|
|
res->chars.resize(res_chars_size + n);
|
|
|
|
memcpySmallAllowReadWriteOverflow15(&res->chars[res_chars_size], data_pos, n);
|
|
|
|
res_chars_size += n;
|
|
|
|
}
|
|
|
|
data_pos += n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
filt_pos += SIMD_BYTES;
|
|
|
|
}
|
2017-03-11 04:41:28 +00:00
|
|
|
#endif
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t res_chars_size = res->chars.size();
|
|
|
|
while (filt_pos < filt_end)
|
|
|
|
{
|
|
|
|
if (*filt_pos)
|
|
|
|
{
|
|
|
|
res->chars.resize(res_chars_size + n);
|
|
|
|
memcpySmallAllowReadWriteOverflow15(&res->chars[res_chars_size], data_pos, n);
|
|
|
|
res_chars_size += n;
|
|
|
|
}
|
|
|
|
|
|
|
|
++filt_pos;
|
|
|
|
data_pos += n;
|
|
|
|
}
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
2019-02-18 19:44:26 +00:00
|
|
|
ColumnPtr ColumnFixedString::permute(const Permutation & perm, size_t limit) const
|
2017-03-11 00:38:30 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t col_size = size();
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (limit == 0)
|
|
|
|
limit = col_size;
|
|
|
|
else
|
|
|
|
limit = std::min(col_size, limit);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (perm.size() < limit)
|
|
|
|
throw Exception("Size of permutation is less than required.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (limit == 0)
|
2017-12-14 01:43:19 +00:00
|
|
|
return ColumnFixedString::create(n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-12-14 03:56:56 +00:00
|
|
|
auto res = ColumnFixedString::create(n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2018-11-25 00:08:50 +00:00
|
|
|
Chars & res_chars = res->chars;
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
res_chars.resize(n * limit);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t offset = 0;
|
|
|
|
for (size_t i = 0; i < limit; ++i, offset += n)
|
|
|
|
memcpySmallAllowReadWriteOverflow15(&res_chars[offset], &chars[perm[i] * n], n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 16:40:25 +00:00
|
|
|
|
2019-02-18 17:28:53 +00:00
|
|
|
ColumnPtr ColumnFixedString::index(const IColumn & indexes, size_t limit) const
|
2018-04-23 16:40:25 +00:00
|
|
|
{
|
|
|
|
return selectIndexImpl(*this, indexes, limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename Type>
|
2019-02-18 17:28:53 +00:00
|
|
|
ColumnPtr ColumnFixedString::indexImpl(const PaddedPODArray<Type> & indexes, size_t limit) const
|
2018-04-23 16:40:25 +00:00
|
|
|
{
|
|
|
|
if (limit == 0)
|
|
|
|
return ColumnFixedString::create(n);
|
|
|
|
|
|
|
|
auto res = ColumnFixedString::create(n);
|
|
|
|
|
2018-11-25 00:08:50 +00:00
|
|
|
Chars & res_chars = res->chars;
|
2018-04-23 16:40:25 +00:00
|
|
|
|
|
|
|
res_chars.resize(n * limit);
|
|
|
|
|
|
|
|
size_t offset = 0;
|
|
|
|
for (size_t i = 0; i < limit; ++i, offset += n)
|
|
|
|
memcpySmallAllowReadWriteOverflow15(&res_chars[offset], &chars[indexes[i] * n], n);
|
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2018-04-23 16:40:25 +00:00
|
|
|
}
|
|
|
|
|
2018-03-20 14:17:09 +00:00
|
|
|
ColumnPtr ColumnFixedString::replicate(const Offsets & offsets) const
|
2017-03-11 00:38:30 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t col_size = size();
|
|
|
|
if (col_size != offsets.size())
|
|
|
|
throw Exception("Size of offsets doesn't match size of column.", ErrorCodes::SIZES_OF_COLUMNS_DOESNT_MATCH);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-12-14 03:56:56 +00:00
|
|
|
auto res = ColumnFixedString::create(n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (0 == col_size)
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2018-11-25 00:08:50 +00:00
|
|
|
Chars & res_chars = res->chars;
|
2017-04-01 07:20:54 +00:00
|
|
|
res_chars.resize(n * offsets.back());
|
2017-03-11 00:38:30 +00:00
|
|
|
|
2017-12-15 21:32:25 +00:00
|
|
|
Offset curr_offset = 0;
|
2017-04-01 07:20:54 +00:00
|
|
|
for (size_t i = 0; i < col_size; ++i)
|
|
|
|
for (size_t next_offset = offsets[i]; curr_offset < next_offset; ++curr_offset)
|
|
|
|
memcpySmallAllowReadWriteOverflow15(&res->chars[curr_offset * n], &chars[i * n], n);
|
2017-03-11 00:38:30 +00:00
|
|
|
|
Get rid of useless std::move to get NRVO
http://eel.is/c++draft/class.copy.elision#:constructor,copy,elision
Some quote:
> Speaking of RVO, return std::move(w); prohibits it. It means "use move constructor or fail to compile", whereas return w; means "use RVO, and if you can't, use move constructor, and if you can't, use copy constructor, and if you can't, fail to compile."
There is one exception to this rule:
```cpp
Block FilterBlockInputStream::removeFilterIfNeed(Block && block)
{
if (block && remove_filter)
block.erase(static_cast<size_t>(filter_column));
return std::move(block);
}
```
because references are not eligible for NRVO, which is another rule "always move rvalue references and forward universal references" that takes precedence.
2018-08-27 14:04:22 +00:00
|
|
|
return res;
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
2017-07-06 13:54:55 +00:00
|
|
|
void ColumnFixedString::gather(ColumnGathererStream & gatherer)
|
|
|
|
{
|
|
|
|
gatherer.gather(*this);
|
|
|
|
}
|
|
|
|
|
2017-03-11 00:38:30 +00:00
|
|
|
void ColumnFixedString::getExtremes(Field & min, Field & max) const
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
min = String();
|
|
|
|
max = String();
|
2017-09-07 13:22:25 +00:00
|
|
|
|
|
|
|
size_t col_size = size();
|
|
|
|
|
|
|
|
if (col_size == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
size_t min_idx = 0;
|
|
|
|
size_t max_idx = 0;
|
|
|
|
|
|
|
|
less<true> less_op(*this);
|
|
|
|
|
|
|
|
for (size_t i = 1; i < col_size; ++i)
|
|
|
|
{
|
|
|
|
if (less_op(i, min_idx))
|
|
|
|
min_idx = i;
|
2017-09-14 11:52:22 +00:00
|
|
|
else if (less_op(max_idx, i))
|
2017-09-07 13:22:25 +00:00
|
|
|
max_idx = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
get(min_idx, min);
|
|
|
|
get(max_idx, max);
|
2017-03-11 00:38:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|