-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathc-string-union.cc
More file actions
120 lines (93 loc) · 2.64 KB
/
Copy pathc-string-union.cc
File metadata and controls
120 lines (93 loc) · 2.64 KB
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
#include <cstddef>
#include <string>
#include <memory>
#include <type_traits>
#include <vector>
#include <iostream>
#include <cassert>
template <class Char, class Traits=std::char_traits<Char>,
class Alloc=std::allocator<Char> >
class basic_c_string {
public:
static_assert(std::is_empty<Alloc>::value,
"C-aliasable string cannot hold stateful allocators");
using traits_type = Traits;
using value_type = Char;
using allocator_type = Alloc;
using size_type = typename std::allocator_traits<Alloc>::size_type;
using difference_type = typename std::allocator_traits<Alloc>::difference_type;
using reference = Char&;
using const_reference = const Char&;
using pointer = typename std::allocator_traits<Alloc>::pointer;
using const_pointer = typename std::allocator_traits<Alloc>::const_pointer;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
union storage_t {
Char ch;
size_type sz;
};
storage_t* storage;
using sa = typename std::allocator_traits<Alloc>::template rebind_alloc<storage_t>;
using sa_traits = std::allocator_traits<sa>;
static storage_t* allocate(size_type n)
{
auto a = sa();
return sa_traits::allocate(
a,
((n+1)*sizeof(Char)+sizeof(size_type)-1) / sizeof(size_type) // (n+1 + size-1)/size, ceil(n+1/size)
+ 2
) + 2;
}
size_type& sizeref() const
{
return storage[-1].sz;
}
size_type& capacityref() const
{
return storage[-2].sz;
}
public:
operator Char*() const
{
return reinterpret_cast<Char*>(storage);
}
basic_c_string()
: storage(0)
{}
basic_c_string(size_type count, Char ch)
: storage(allocate(count))
{
sizeref() = count;
capacityref() = count;
Traits::assign(reinterpret_cast<Char*>(storage), count, ch);
storage[count].ch = 0;
}
~basic_c_string()
{
auto a = sa();
if (storage)
sa_traits::deallocate(a, storage-2, capacityref()); // FIXME capacityref is not the allocated count
}
size_type size() const
{
return storage ? sizeref() : 0;
}
size_type capacity() const
{
return storage ? capacityref() : 0;
}
};
using c_string = basic_c_string<char>;
static_assert(sizeof(c_string) == sizeof(char*), "size mismatch?");
int main()
{
// std::vector<c_string> strs = { {3, 'a'} };
// const char** p_strs = reinterpret_cast<const char**>(strs.data());
c_string strs[] {{3, 'a'}};
char** p_strs = reinterpret_cast<char**>(strs);
assert(std::string("aaa") == p_strs[0]);
return 0;
}