1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/common/types/string_type.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/common/constants.hpp" |
12 | #include <cstring> |
13 | #include <cassert> |
14 | |
15 | namespace duckdb { |
16 | |
17 | struct string_t { |
18 | friend struct StringComparisonOperators; |
19 | friend class StringSegment; |
20 | |
21 | public: |
22 | static constexpr idx_t PREFIX_LENGTH = 4 * sizeof(char); |
23 | static constexpr idx_t INLINE_LENGTH = 12; |
24 | |
25 | string_t() = default; |
26 | string_t(uint32_t len) : length(len) { |
27 | memset(prefix, 0, PREFIX_LENGTH); |
28 | value_.data = nullptr; |
29 | } |
30 | string_t(const char *data, uint32_t len) : length(len) { |
31 | assert(data || length == 0); |
32 | if (IsInlined()) { |
33 | // zero initialize the prefix first |
34 | // this makes sure that strings with length smaller than 4 still have an equal prefix |
35 | memset(prefix, 0, PREFIX_LENGTH); |
36 | if (length == 0) { |
37 | return; |
38 | } |
39 | // small string: inlined |
40 | memcpy(prefix, data, length); |
41 | prefix[length] = '\0'; |
42 | } else { |
43 | // large string: store pointer |
44 | memcpy(prefix, data, PREFIX_LENGTH); |
45 | value_.data = (char *)data; |
46 | } |
47 | } |
48 | string_t(const char *data) : string_t(data, strlen(data)) { |
49 | } |
50 | string_t(const string &value) : string_t(value.c_str(), value.size()) { |
51 | } |
52 | |
53 | bool IsInlined() const { |
54 | return length < INLINE_LENGTH; |
55 | } |
56 | |
57 | char *GetData() { |
58 | return IsInlined() ? (char *)prefix : value_.data; |
59 | } |
60 | |
61 | const char *GetData() const { |
62 | return IsInlined() ? (const char *)prefix : value_.data; |
63 | } |
64 | |
65 | const char *GetPrefix() const { |
66 | return prefix; |
67 | } |
68 | |
69 | idx_t GetSize() const { |
70 | return length; |
71 | } |
72 | |
73 | string GetString() const { |
74 | return string(GetData(), GetSize()); |
75 | } |
76 | |
77 | void Finalize() { |
78 | // set trailing NULL byte |
79 | auto dataptr = (char *)GetData(); |
80 | dataptr[length] = '\0'; |
81 | if (length < INLINE_LENGTH) { |
82 | // fill prefix with zeros if the length is smaller than the prefix length |
83 | for (idx_t i = length; i < PREFIX_LENGTH; i++) { |
84 | prefix[i] = '\0'; |
85 | } |
86 | } else { |
87 | // copy the data into the prefix |
88 | memcpy(prefix, dataptr, PREFIX_LENGTH); |
89 | } |
90 | } |
91 | |
92 | void Verify(); |
93 | |
94 | private: |
95 | uint32_t length; |
96 | char prefix[4]; |
97 | union { |
98 | char inlined[8]; |
99 | char *data; |
100 | } value_; |
101 | }; |
102 | |
103 | }; // namespace duckdb |
104 | |