-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathtypes.hh
1750 lines (1595 loc) · 63.9 KB
/
types.hh
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (C) 2014 ScyllaDB
*/
/*
* This file is part of Scylla.
*
* Scylla is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Scylla is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <experimental/optional>
#include <boost/functional/hash.hpp>
#include <iosfwd>
#include "data/cell.hh"
#include <sstream>
#include "core/sstring.hh"
#include "core/shared_ptr.hh"
#include "utils/UUID.hh"
#include "net/byteorder.hh"
#include "db_clock.hh"
#include "bytes.hh"
#include "log.hh"
#include "atomic_cell.hh"
#include "cql_serialization_format.hh"
#include "tombstone.hh"
#include "to_string.hh"
#include "duration.hh"
#include "marshal_exception.hh"
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/numeric.hpp>
#include <boost/range/combine.hpp>
#include "net/ip.hh"
#include <seastar/net/inet_address.hh>
#include "util/backtrace.hh"
#include "hashing.hh"
#include <boost/multiprecision/cpp_int.hpp> // FIXME: remove somehow
#include "stdx.hh"
#include "utils/fragmented_temporary_buffer.hh"
class tuple_type_impl;
class big_decimal;
namespace Json {
class Value;
}
namespace cql3 {
class cql3_type;
class column_specification;
shared_ptr<cql3_type> make_cql3_tuple_type(shared_ptr<const tuple_type_impl> t);
}
// Specifies position in a lexicographically ordered sequence
// relative to some value.
//
// For example, if used with a value "bc" with lexicographical ordering on strings,
// each enum value represents the following positions in an example sequence:
//
// aa
// aaa
// b
// ba
// --> before_all_prefixed
// bc
// --> before_all_strictly_prefixed
// bca
// bcd
// --> after_all_prefixed
// bd
// bda
// c
// ca
//
enum class lexicographical_relation : int8_t {
before_all_prefixed,
before_all_strictly_prefixed,
after_all_prefixed
};
// Like std::lexicographical_compare but injects values from shared sequence (types) to the comparator
// Compare is an abstract_type-aware less comparator, which takes the type as first argument.
template <typename TypesIterator, typename InputIt1, typename InputIt2, typename Compare>
bool lexicographical_compare(TypesIterator types, InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, Compare comp) {
while (first1 != last1 && first2 != last2) {
if (comp(*types, *first1, *first2)) {
return true;
}
if (comp(*types, *first2, *first1)) {
return false;
}
++first1;
++first2;
++types;
}
return (first1 == last1) && (first2 != last2);
}
// Like std::lexicographical_compare but injects values from shared sequence
// (types) to the comparator. Compare is an abstract_type-aware trichotomic
// comparator, which takes the type as first argument.
//
// A trichotomic comparator returns an integer which is less, equal or greater
// than zero when the first value is respectively smaller, equal or greater
// than the second value.
template <typename TypesIterator, typename InputIt1, typename InputIt2, typename Compare>
int lexicographical_tri_compare(TypesIterator types_first, TypesIterator types_last,
InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
Compare comp,
lexicographical_relation relation1 = lexicographical_relation::before_all_strictly_prefixed,
lexicographical_relation relation2 = lexicographical_relation::before_all_strictly_prefixed) {
while (types_first != types_last && first1 != last1 && first2 != last2) {
auto c = comp(*types_first, *first1, *first2);
if (c) {
return c;
}
++first1;
++first2;
++types_first;
}
bool e1 = first1 == last1;
bool e2 = first2 == last2;
if (e1 && e2) {
return static_cast<int>(relation1) - static_cast<int>(relation2);
}
if (e2) {
return relation2 == lexicographical_relation::after_all_prefixed ? -1 : 1;
} else if (e1) {
return relation1 == lexicographical_relation::after_all_prefixed ? 1 : -1;
} else {
return 0;
}
}
// Trichotomic version of std::lexicographical_compare()
//
// Returns an integer which is less, equal or greater than zero when the first value
// is respectively smaller, equal or greater than the second value.
template <typename InputIt1, typename InputIt2, typename Compare>
int lexicographical_tri_compare(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
Compare comp,
lexicographical_relation relation1 = lexicographical_relation::before_all_strictly_prefixed,
lexicographical_relation relation2 = lexicographical_relation::before_all_strictly_prefixed) {
while (first1 != last1 && first2 != last2) {
auto c = comp(*first1, *first2);
if (c) {
return c;
}
++first1;
++first2;
}
bool e1 = first1 == last1;
bool e2 = first2 == last2;
if (e1 == e2) {
return static_cast<int>(relation1) - static_cast<int>(relation2);
}
if (e2) {
return relation2 == lexicographical_relation::after_all_prefixed ? -1 : 1;
} else {
return relation1 == lexicographical_relation::after_all_prefixed ? 1 : -1;
}
}
// A trichotomic comparator for prefix equality total ordering.
// In this ordering, two sequences are equal iff any of them is a prefix
// of the another. Otherwise, lexicographical ordering determines the order.
//
// 'comp' is an abstract_type-aware trichotomic comparator, which takes the
// type as first argument.
//
template <typename TypesIterator, typename InputIt1, typename InputIt2, typename Compare>
int prefix_equality_tri_compare(TypesIterator types, InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, Compare comp) {
while (first1 != last1 && first2 != last2) {
auto c = comp(*types, *first1, *first2);
if (c) {
return c;
}
++first1;
++first2;
++types;
}
return 0;
}
// Returns true iff the second sequence is a prefix of the first sequence
// Equality is an abstract_type-aware equality checker which takes the type as first argument.
template <typename TypesIterator, typename InputIt1, typename InputIt2, typename Equality>
bool is_prefixed_by(TypesIterator types, InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, Equality equality) {
while (first1 != last1 && first2 != last2) {
if (!equality(*types, *first1, *first2)) {
return false;
}
++first1;
++first2;
++types;
}
return first2 == last2;
}
struct runtime_exception : public std::exception {
sstring _why;
public:
runtime_exception(sstring why) : _why(sstring("runtime error: ") + why) {}
virtual const char* what() const noexcept override { return _why.c_str(); }
};
struct empty_t {};
class empty_value_exception : public std::exception {
public:
virtual const char* what() const noexcept override {
return "Unexpected empty value";
}
};
// Cassandra has a notion of empty values even for scalars (i.e. int). This is
// distinct from NULL which means deleted or never set. It is serialized
// as a zero-length byte array (whereas NULL is serialized as a negative-length
// byte array).
template <typename T>
class emptyable {
// We don't use optional<>, to avoid lots of ifs during the copy and move constructors
static_assert(std::is_default_constructible<T>::value, "must be default constructible");
bool _is_empty = false;
T _value;
public:
// default-constructor defaults to a non-empty value, since empty is the
// exception rather than the rule
emptyable() : _value{} {}
emptyable(const T& x) : _value(x) {}
emptyable(T&& x) : _value(std::move(x)) {}
emptyable(empty_t) : _is_empty(true) {}
template <typename... U>
emptyable(U&&... args) : _value(std::forward<U>(args)...) {}
bool empty() const { return _is_empty; }
operator const T& () const { verify(); return _value; }
operator T&& () && { verify(); return std::move(_value); }
const T& get() const & { verify(); return _value; }
T&& get() && { verify(); return std::move(_value); }
private:
void verify() const {
if (_is_empty) {
throw empty_value_exception();
}
}
};
template <typename T>
inline
bool
operator==(const emptyable<T>& me1, const emptyable<T>& me2) {
if (me1.empty() && me2.empty()) {
return true;
}
if (me1.empty() != me2.empty()) {
return false;
}
return me1.get() == me2.get();
}
template <typename T>
inline
bool
operator<(const emptyable<T>& me1, const emptyable<T>& me2) {
if (me1.empty()) {
if (me2.empty()) {
return false;
} else {
return true;
}
}
if (me2.empty()) {
return false;
} else {
return me1.get() < me2.get();
}
}
// Checks whether T::empty() const exists and returns bool
template <typename T>
class has_empty {
template <typename X>
constexpr static auto check(const X* x) -> std::enable_if_t<std::is_same<bool, decltype(x->empty())>::value, bool> {
return true;
}
template <typename X>
constexpr static auto check(...) -> bool {
return false;
}
public:
constexpr static bool value = check<T>(nullptr);
};
template <typename T>
using maybe_empty =
std::conditional_t<has_empty<T>::value, T, emptyable<T>>;
class abstract_type;
class data_value;
struct simple_date_native_type {
using primary_type = uint32_t;
primary_type days;
};
struct timestamp_native_type {
using primary_type = db_clock::time_point;
primary_type tp;
};
struct time_native_type {
using primary_type = int64_t;
primary_type nanoseconds;
};
struct timeuuid_native_type {
using primary_type = utils::UUID;
primary_type uuid;
};
using data_type = shared_ptr<const abstract_type>;
template <typename T>
const T& value_cast(const data_value& value);
template <typename T>
T&& value_cast(data_value&& value);
class data_value {
void* _value; // FIXME: use "small value optimization" for small types
data_type _type;
private:
data_value(void* value, data_type type) : _value(value), _type(std::move(type)) {}
template <typename T>
static data_value make_new(data_type type, T&& value);
public:
~data_value();
data_value(const data_value&);
data_value(data_value&& x) noexcept : _value(x._value), _type(std::move(x._type)) {
x._value = nullptr;
}
// common conversions from C++ types to database types
// note: somewhat dangerous, consider a factory function instead
explicit data_value(bytes);
data_value(sstring);
data_value(const char*);
data_value(bool);
data_value(int8_t);
data_value(int16_t);
data_value(int32_t);
data_value(int64_t);
data_value(utils::UUID);
data_value(float);
data_value(double);
data_value(net::ipv4_address);
data_value(seastar::net::inet_address);
data_value(simple_date_native_type);
data_value(timestamp_native_type);
data_value(time_native_type);
data_value(timeuuid_native_type);
data_value(db_clock::time_point);
data_value(boost::multiprecision::cpp_int);
data_value(big_decimal);
data_value(cql_duration);
explicit data_value(std::experimental::optional<bytes>);
template <typename NativeType>
data_value(std::experimental::optional<NativeType>);
template <typename NativeType>
data_value(const std::unordered_set<NativeType>&);
data_value& operator=(const data_value&);
data_value& operator=(data_value&&);
const data_type& type() const {
return _type;
}
bool is_null() const { // may return false negatives for strings etc.
return !_value;
}
size_t serialized_size() const;
void serialize(bytes::iterator& out) const;
bytes serialize() const;
friend inline bool operator==(const data_value& x, const data_value& y);
friend inline bool operator!=(const data_value& x, const data_value& y);
friend class abstract_type;
static data_value make_null(data_type type) {
return data_value(nullptr, std::move(type));
}
template <typename T>
static data_value make(data_type type, std::unique_ptr<T> value) {
return data_value(value.release(), std::move(type));
}
friend class empty_type_impl;
template <typename T> friend const T& value_cast(const data_value&);
template <typename T> friend T&& value_cast(data_value&&);
friend std::ostream& operator<<(std::ostream&, const data_value&);
friend data_value make_tuple_value(data_type, maybe_empty<std::vector<data_value>>);
friend data_value make_set_value(data_type, maybe_empty<std::vector<data_value>>);
friend data_value make_list_value(data_type, maybe_empty<std::vector<data_value>>);
friend data_value make_map_value(data_type, maybe_empty<std::vector<std::pair<data_value, data_value>>>);
friend data_value make_user_value(data_type, std::vector<data_value>);
};
class serialized_compare;
class serialized_tri_compare;
class user_type_impl;
// Unsafe to access across shards unless otherwise noted.
class abstract_type : public enable_shared_from_this<abstract_type> {
sstring _name;
std::optional<uint32_t> _value_length_if_fixed;
data::type_imr_descriptor _imr_state;
public:
abstract_type(sstring name, std::optional<uint32_t> value_length_if_fixed, data::type_info ti)
: _name(name), _value_length_if_fixed(std::move(value_length_if_fixed)), _imr_state(ti) {}
virtual ~abstract_type() {}
const data::type_imr_descriptor& imr_state() const { return _imr_state; }
virtual void serialize(const void* value, bytes::iterator& out) const = 0;
void serialize(const data_value& value, bytes::iterator& out) const {
return serialize(get_value_ptr(value), out);
}
virtual size_t serialized_size(const void* value) const = 0;
virtual bool less(bytes_view v1, bytes_view v2) const = 0;
// returns a callable that can be called with two byte_views, and calls this->less() on them.
serialized_compare as_less_comparator() const ;
serialized_tri_compare as_tri_comparator() const ;
static data_type parse_type(const sstring& name);
virtual size_t hash(bytes_view v) const = 0;
virtual bool equal(bytes_view v1, bytes_view v2) const {
if (is_byte_order_equal()) {
return compare_unsigned(v1, v2) == 0;
}
return compare(v1, v2) == 0;
}
virtual int32_t compare(bytes_view v1, bytes_view v2) const {
if (less(v1, v2)) {
return -1;
} else if (less(v2, v1)) {
return 1;
} else {
return 0;
}
}
virtual data_value deserialize(bytes_view v) const = 0;
data_value deserialize_value(bytes_view v) const {
return deserialize(v);
};
virtual void validate(bytes_view v) const {
// FIXME
}
virtual void validate(const fragmented_temporary_buffer::view& view) const {
with_linearized(view, [this] (bytes_view bv) {
validate(bv);
});
}
virtual void validate_collection_member(bytes_view v, const bytes& collection_name) const {
validate(v);
}
virtual bool is_compatible_with(const abstract_type& previous) const {
return equals(previous);
}
/*
* Types which are wrappers over other types should override this.
* For example the reversed_type returns the type it is reversing.
*/
virtual shared_ptr<const abstract_type> underlying_type() const {
return shared_from_this();
}
/**
* Returns true if values of the other AbstractType can be read and "reasonably" interpreted by the this
* AbstractType. Note that this is a weaker version of isCompatibleWith, as it does not require that both type
* compare values the same way.
*
* The restriction on the other type being "reasonably" interpreted is to prevent, for example, IntegerType from
* being compatible with all other types. Even though any byte string is a valid IntegerType value, it doesn't
* necessarily make sense to interpret a UUID or a UTF8 string as an integer.
*
* Note that a type should be compatible with at least itself.
*/
bool is_value_compatible_with(const abstract_type& other) const {
return is_value_compatible_with_internal(*other.underlying_type());
}
bool equals(const shared_ptr<const abstract_type>& other) const {
return equals(*other);
}
virtual bool references_user_type(const sstring& keyspace, const bytes& name) const = 0;
virtual std::experimental::optional<data_type> update_user_type(const shared_ptr<const user_type_impl> updated) const = 0;
virtual bool references_duration() const {
return false;
}
std::optional<uint32_t> value_length_if_fixed() const {
return _value_length_if_fixed;
}
protected:
virtual bool equals(const abstract_type& other) const {
return this == &other;
}
/**
* Needed to handle ReversedType in value-compatibility checks. Subclasses should implement this instead of
* is_value_compatible_with().
*/
virtual bool is_value_compatible_with_internal(const abstract_type& other) const {
return is_compatible_with(other);
}
public:
bytes decompose(const data_value& value) const {
if (!value._value) {
return {};
}
bytes b(bytes::initialized_later(), serialized_size(value._value));
auto i = b.begin();
serialize(value._value, i);
return b;
}
// Safe to call across shards
const sstring& name() const {
return _name;
}
virtual bool is_byte_order_comparable() const {
return false;
}
/**
* When returns true then equal values have the same byte representation and if byte
* representation is different, the values are not equal.
*
* When returns false, nothing can be inferred.
*/
virtual bool is_byte_order_equal() const {
// If we're byte order comparable, then we must also be byte order equal.
return is_byte_order_comparable();
}
virtual sstring get_string(const bytes& b) const {
validate(b);
return to_string(b);
}
virtual sstring to_string(const bytes& b) const = 0;
virtual bytes from_string(sstring_view text) const = 0;
virtual sstring to_json_string(const bytes& b) const = 0;
sstring to_json_string(const bytes_opt& b) const {
return b ? to_json_string(*b) : "null";
}
virtual bytes from_json_object(const Json::Value& value, cql_serialization_format sf) const = 0;
virtual bool is_counter() const { return false; }
virtual bool is_collection() const { return false; }
virtual bool is_multi_cell() const { return false; }
virtual bool is_atomic() const { return !is_multi_cell(); }
virtual bool is_reversed() const { return false; }
virtual bool is_tuple() const { return false; }
virtual bool is_user_type() const { return false; }
virtual ::shared_ptr<cql3::cql3_type> as_cql3_type() const = 0;
virtual shared_ptr<const abstract_type> freeze() const { return shared_from_this(); }
friend class list_type_impl;
protected:
// native_value_* methods are virualized versions of native_type's
// sizeof/alignof/copy-ctor/move-ctor etc.
virtual size_t native_value_size() const = 0;
virtual size_t native_value_alignment() const = 0;
virtual void native_value_copy(const void* from, void* to) const = 0;
virtual void native_value_move(void* from, void* to) const = 0;
virtual void* native_value_clone(const void* from) const = 0;
virtual void native_value_destroy(void* object) const = 0;
virtual void native_value_delete(void* object) const = 0;
virtual const std::type_info& native_typeid() const = 0;
// abstract_type is a friend of data_value, but derived classes are not.
static const void* get_value_ptr(const data_value& v) {
return v._value;
}
friend void write_collection_value(bytes::iterator& out, cql_serialization_format sf, data_type type, const data_value& value);
friend class tuple_type_impl;
friend class data_value;
friend class reversed_type_impl;
template <typename T> friend const T& value_cast(const data_value& value);
template <typename T> friend T&& value_cast(data_value&& value);
friend bool operator==(const abstract_type& x, const abstract_type& y);
static sstring quote_json_string(const sstring& s);
};
inline bool operator==(const abstract_type& x, const abstract_type& y)
{
return x.equals(y);
}
inline
size_t
data_value::serialized_size() const {
return _type->serialized_size(_value);
}
inline
void
data_value::serialize(bytes::iterator& out) const {
return _type->serialize(_value, out);
}
inline
bytes
data_value::serialize() const {
if (!_value) {
return {};
}
bytes b(bytes::initialized_later(), serialized_size());
auto i = b.begin();
serialize(i);
return b;
}
template <typename T>
inline
data_value
data_value::make_new(data_type type, T&& v) {
maybe_empty<std::remove_reference_t<T>> value(std::forward<T>(v));
return data_value(type->native_value_clone(&value), type);
}
template <typename T>
const T& value_cast(const data_value& value) {
if (typeid(maybe_empty<T>) != value.type()->native_typeid()) {
throw std::bad_cast();
}
if (value.is_null()) {
throw std::runtime_error("value is null");
}
return *reinterpret_cast<maybe_empty<T>*>(value._value);
}
template <typename T>
T&& value_cast(data_value&& value) {
if (typeid(maybe_empty<T>) != value.type()->native_typeid()) {
throw std::bad_cast();
}
if (value.is_null()) {
throw std::runtime_error("value is null");
}
return std::move(*reinterpret_cast<maybe_empty<T>*>(value._value));
}
// CRTP: implements translation between a native_type (C++ type) to abstract_type
// AbstractType is parametrized because we want a
// abstract_type -> collection_type_impl -> map_type
// type hierarchy, and native_type is only known at the last step.
template <typename NativeType, typename AbstractType = abstract_type>
class concrete_type : public AbstractType {
public:
using native_type = maybe_empty<NativeType>;
using AbstractType::AbstractType;
protected:
virtual size_t native_value_size() const override {
return sizeof(native_type);
}
virtual size_t native_value_alignment() const override {
return alignof(native_type);
}
virtual void native_value_copy(const void* from, void* to) const override {
new (to) native_type(*reinterpret_cast<const native_type*>(from));
}
virtual void native_value_move(void* from, void* to) const override {
new (to) native_type(std::move(*reinterpret_cast<native_type*>(from)));
}
virtual void native_value_destroy(void* object) const override {
reinterpret_cast<native_type*>(object)->~native_type();
}
virtual void native_value_delete(void* object) const override {
delete reinterpret_cast<native_type*>(object);
}
virtual void* native_value_clone(const void* object) const override {
return new native_type(*reinterpret_cast<const native_type*>(object));
}
virtual const std::type_info& native_typeid() const override {
return typeid(native_type);
}
virtual bool references_user_type(const sstring& keyspace, const bytes& name) const override {
return false;
}
virtual std::experimental::optional<data_type> update_user_type(const shared_ptr<const user_type_impl> updated) const override {
return std::experimental::nullopt;
}
protected:
data_value make_value(std::unique_ptr<native_type> value) const {
return data_value::make(this->shared_from_this(), std::move(value));
}
data_value make_value(native_type value) const {
return make_value(std::make_unique<native_type>(std::move(value)));
}
data_value make_null() const {
return data_value::make_null(this->shared_from_this());
}
data_value make_empty() const {
return make_value(native_type(empty_t()));
}
const native_type& from_value(const void* v) const {
return *reinterpret_cast<const native_type*>(v);
}
const native_type& from_value(const data_value& v) const {
return this->from_value(AbstractType::get_value_ptr(v));
}
};
inline bool operator==(const data_value& x, const data_value& y)
{
return x._type->equals(y._type) && x._type->equal(x._type->decompose(x), y._type->decompose(y));
}
inline bool operator!=(const data_value& x, const data_value& y)
{
return !(x == y);
}
using bytes_view_opt = std::experimental::optional<bytes_view>;
static inline
bool optional_less_compare(data_type t, bytes_view_opt e1, bytes_view_opt e2) {
if (bool(e1) != bool(e2)) {
return bool(e2);
}
if (!e1) {
return false;
}
return t->less(*e1, *e2);
}
static inline
bool optional_equal(data_type t, bytes_view_opt e1, bytes_view_opt e2) {
if (bool(e1) != bool(e2)) {
return false;
}
if (!e1) {
return true;
}
return t->equal(*e1, *e2);
}
static inline
bool less_compare(data_type t, bytes_view e1, bytes_view e2) {
return t->less(e1, e2);
}
static inline
int tri_compare(data_type t, bytes_view e1, bytes_view e2) {
return t->compare(e1, e2);
}
inline
int
tri_compare_opt(data_type t, bytes_view_opt v1, bytes_view_opt v2) {
if (!v1 || !v2) {
return int(bool(v1)) - int(bool(v2));
} else {
return tri_compare(std::move(t), *v1, *v2);
}
}
static inline
bool equal(data_type t, bytes_view e1, bytes_view e2) {
return t->equal(e1, e2);
}
class row_tombstone;
class collection_type_impl : public abstract_type {
static logging::logger _logger;
static thread_local std::unordered_map<data_type, shared_ptr<cql3::cql3_type>> _cql3_type_cache; // initialized on demand
public:
static constexpr size_t max_elements = 65535;
class kind {
std::function<shared_ptr<cql3::column_specification> (shared_ptr<cql3::column_specification> collection, bool is_key)> _impl;
public:
kind(std::function<shared_ptr<cql3::column_specification> (shared_ptr<cql3::column_specification> collection, bool is_key)> impl)
: _impl(std::move(impl)) {}
shared_ptr<cql3::column_specification> make_collection_receiver(shared_ptr<cql3::column_specification> collection, bool is_key) const;
static const kind map;
static const kind set;
static const kind list;
};
const kind& _kind;
protected:
explicit collection_type_impl(sstring name, const kind& k)
: abstract_type(std::move(name), {}, data::type_info::make_collection()), _kind(k) {}
virtual sstring cql3_type_name() const = 0;
public:
// representation of a collection mutation, key/value pairs, value is a mutation itself
struct mutation {
tombstone tomb;
std::vector<std::pair<bytes, atomic_cell>> cells;
// Expires cells based on query_time. Expires tombstones based on max_purgeable and gc_before.
// Removes cells covered by tomb or this->tomb.
bool compact_and_expire(row_tombstone tomb, gc_clock::time_point query_time,
can_gc_fn&, gc_clock::time_point gc_before);
};
struct mutation_view {
tombstone tomb;
std::vector<std::pair<bytes_view, atomic_cell_view>> cells;
mutation materialize(const collection_type_impl&) const;
};
virtual data_type name_comparator() const = 0;
virtual data_type value_comparator() const = 0;
shared_ptr<cql3::column_specification> make_collection_receiver(shared_ptr<cql3::column_specification> collection, bool is_key) const;
virtual bool is_collection() const override { return true; }
bool is_map() const { return &_kind == &kind::map; }
bool is_set() const { return &_kind == &kind::set; }
bool is_list() const { return &_kind == &kind::list; }
std::vector<atomic_cell> enforce_limit(std::vector<atomic_cell>, int version) const;
virtual std::vector<bytes> serialized_values(std::vector<atomic_cell> cells) const = 0;
bytes serialize_for_native_protocol(std::vector<atomic_cell> cells, int version) const;
virtual bool is_compatible_with(const abstract_type& previous) const override;
virtual bool is_value_compatible_with_internal(const abstract_type& other) const override;
virtual bool is_compatible_with_frozen(const collection_type_impl& previous) const = 0;
virtual bool is_value_compatible_with_frozen(const collection_type_impl& previous) const = 0;
virtual shared_ptr<cql3::cql3_type> as_cql3_type() const override;
template <typename BytesViewIterator>
static bytes pack(BytesViewIterator start, BytesViewIterator finish, int elements, cql_serialization_format sf);
// requires linearized collection_mutation_view, lifetime
mutation_view deserialize_mutation_form(bytes_view in) const;
bool is_empty(collection_mutation_view in) const;
bool is_any_live(collection_mutation_view in, tombstone tomb = tombstone(), gc_clock::time_point now = gc_clock::time_point::min()) const;
api::timestamp_type last_update(collection_mutation_view in) const;
virtual bytes to_value(mutation_view mut, cql_serialization_format sf) const = 0;
bytes to_value(collection_mutation_view mut, cql_serialization_format sf) const;
// FIXME: use iterators?
collection_mutation serialize_mutation_form(const mutation& mut) const;
collection_mutation serialize_mutation_form(mutation_view mut) const;
collection_mutation serialize_mutation_form_only_live(mutation_view mut, gc_clock::time_point now) const;
collection_mutation merge(collection_mutation_view a, collection_mutation_view b) const;
collection_mutation difference(collection_mutation_view a, collection_mutation_view b) const;
// Calls Func(atomic_cell_view) for each cell in this collection.
// noexcept if Func doesn't throw.
template<typename Func>
void for_each_cell(collection_mutation_view c, Func&& func) const {
c.data.with_linearized([&] (bytes_view c_bv) {
auto m_view = deserialize_mutation_form(c_bv);
for (auto&& c : m_view.cells) {
func(std::move(c.second));
}
});
}
virtual void serialize(const void* value, bytes::iterator& out, cql_serialization_format sf) const = 0;
virtual data_value deserialize(bytes_view v, cql_serialization_format sf) const = 0;
data_value deserialize_value(bytes_view v, cql_serialization_format sf) const {
return deserialize(v, sf);
}
bytes_opt reserialize(cql_serialization_format from, cql_serialization_format to, bytes_view_opt v) const;
};
using collection_type = shared_ptr<const collection_type_impl>;
template <typename... T>
struct simple_tuple_hash;
template <>
struct simple_tuple_hash<> {
size_t operator()() const { return 0; }
};
template <typename Arg0, typename... Args >
struct simple_tuple_hash<std::vector<Arg0>, Args...> {
size_t operator()(const std::vector<Arg0>& vec, const Args&... args) const {
size_t h0 = 0;
size_t h1;
for (auto&& i : vec) {
h1 = std::hash<Arg0>()(i);
h0 = h0 ^ ((h1 << 7) | (h1 >> (std::numeric_limits<size_t>::digits - 7)));
}
h1 = simple_tuple_hash<Args...>()(args...);
return h0 ^ ((h1 << 7) | (h1 >> (std::numeric_limits<size_t>::digits - 7)));
}
};
template <typename Arg0, typename... Args>
struct simple_tuple_hash<Arg0, Args...> {
size_t operator()(const Arg0& arg0, const Args&... args) const {
size_t h0 = std::hash<Arg0>()(arg0);
size_t h1 = simple_tuple_hash<Args...>()(args...);
return h0 ^ ((h1 << 7) | (h1 >> (std::numeric_limits<size_t>::digits - 7)));
}
};
template <typename InternedType, typename... BaseTypes>
class type_interning_helper {
using key_type = std::tuple<BaseTypes...>;
using value_type = shared_ptr<const InternedType>;
struct hash_type {
size_t operator()(const key_type& k) const {
return apply(simple_tuple_hash<BaseTypes...>(), k);
}
};
using map_type = std::unordered_map<key_type, value_type, hash_type>;
static thread_local map_type _instances;
public:
static shared_ptr<const InternedType> get_instance(BaseTypes... keys) {
auto key = std::make_tuple(keys...);
auto i = _instances.find(key);
if (i == _instances.end()) {
auto v = ::make_shared<InternedType>(std::move(keys)...);
i = _instances.insert(std::make_pair(std::move(key), std::move(v))).first;
}
return i->second;
}
};
template <typename InternedType, typename... BaseTypes>
thread_local typename type_interning_helper<InternedType, BaseTypes...>::map_type
type_interning_helper<InternedType, BaseTypes...>::_instances;
class reversed_type_impl : public abstract_type {
using intern = type_interning_helper<reversed_type_impl, data_type>;
friend struct shared_ptr_make_helper<reversed_type_impl, true>;
data_type _underlying_type;
reversed_type_impl(data_type t)
: abstract_type("org.apache.cassandra.db.marshal.ReversedType(" + t->name() + ")",
t->value_length_if_fixed(), t->imr_state().type_info())
, _underlying_type(t)
{}
protected:
virtual bool is_value_compatible_with_internal(const abstract_type& other) const {
return _underlying_type->is_value_compatible_with(*(other.underlying_type()));
}
public:
virtual int32_t compare(bytes_view v1, bytes_view v2) const override {
return _underlying_type->compare(v2, v1);
}
virtual bool less(bytes_view v1, bytes_view v2) const override {
return _underlying_type->less(v2, v1);
}
virtual bool equal(bytes_view v1, bytes_view v2) const override {
return _underlying_type->equal(v1, v2);
}
virtual void validate(bytes_view v) const override {
_underlying_type->validate(v);
}
virtual void validate_collection_member(bytes_view v, const bytes& collection_name) const override {
_underlying_type->validate_collection_member(v, collection_name);
}
virtual bool is_compatible_with(const abstract_type& previous) const override {
if (previous.is_reversed()) {
return _underlying_type->is_compatible_with(*previous.underlying_type());
}
return false;
}
virtual shared_ptr<const abstract_type> underlying_type() const override {
return _underlying_type;
}
virtual bool is_byte_order_comparable() const override {
return _underlying_type->is_byte_order_comparable();
}
virtual bool is_byte_order_equal() const override {
return _underlying_type->is_byte_order_equal();
}
virtual size_t hash(bytes_view v) const override {
return _underlying_type->hash(v);
}
virtual bool is_reversed() const override { return true; }
virtual bool is_counter() const override {
return _underlying_type->is_counter();
}
virtual bool is_collection() const override {
return _underlying_type->is_collection();
}
virtual bool is_multi_cell() const override {
return _underlying_type->is_multi_cell();
}
virtual void serialize(const void* value, bytes::iterator& out) const override {
_underlying_type->serialize(value, out);
}
virtual size_t serialized_size(const void* value) const override {
return _underlying_type->serialized_size(value);
}
virtual data_value deserialize(bytes_view v) const override {
return _underlying_type->deserialize(v);