]> git.saurik.com Git - cydia.git/blob - Cytore.hpp
Store Package::metadata_ as a pointer, not a Cytore::Offset<>.
[cydia.git] / Cytore.hpp
1 // Copyright Notice (GNU Affero GPL) {{{
2 /* Cyndir - (Awesome) Memory Mapped Dictionary
3 * Copyright (C) 2010 Jay Freeman (saurik)
4 */
5
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 // }}}
21
22 #ifndef CYTORE_HPP
23 #define CYTORE_HPP
24
25 #include <fcntl.h>
26
27 #include <sys/mman.h>
28 #include <sys/stat.h>
29
30 #include <cstdio>
31 #include <cstdlib>
32
33 #include <errno.h>
34 #include <stdint.h>
35 #include <unistd.h>
36
37 #define _assert(test) do \
38 if (!(test)) { \
39 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
40 exit(-1); \
41 } \
42 while (false)
43
44 namespace Cytore {
45
46 static const uint32_t Magic = 'cynd';
47
48 struct Header {
49 uint32_t magic_;
50 uint32_t version_;
51 uint32_t size_;
52 uint32_t reserved_;
53 };
54
55 struct Block {
56 };
57
58 template <typename Target_>
59 class Offset {
60 private:
61 uint32_t offset_;
62
63 public:
64 Offset() :
65 offset_(0)
66 {
67 }
68
69 Offset(uint32_t offset) :
70 offset_(offset)
71 {
72 }
73
74 Offset &operator =(uint32_t offset) {
75 offset_ = offset;
76 return *this;
77 }
78
79 uint32_t GetOffset() const {
80 return offset_;
81 }
82
83 bool IsNull() const {
84 return offset_ == 0;
85 }
86 };
87
88 template <typename Type_>
89 static _finline Type_ Round(Type_ value, Type_ size) {
90 Type_ mask(size - 1);
91 return value + mask & ~mask;
92 }
93
94 template <typename Base_>
95 class File {
96 private:
97 static const unsigned Shift_ = 17;
98 static const size_t Block_ = 1 << Shift_;
99 static const size_t Mask_ = Block_ - 1;
100
101 private:
102 int file_;
103 std::vector<uint8_t *> blocks_;
104
105 Header &Header_() {
106 return *reinterpret_cast<Header *>(blocks_[0]);
107 }
108
109 uint32_t &Size_() {
110 return Header_().size_;
111 }
112
113 void Map_(size_t size) {
114 size_t before(blocks_.size() * Block_);
115 size_t extend(size - before);
116
117 void *data(mmap(NULL, extend, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, file_, before));
118 for (size_t i(0); i != extend >> Shift_; ++i)
119 blocks_.push_back(reinterpret_cast<uint8_t *>(data) + Block_ * i);
120 }
121
122 void Truncate_(size_t capacity) {
123 capacity = Round(capacity, Block_);
124 ftruncate(file_, capacity);
125 Map_(capacity);
126 }
127
128 public:
129 File() :
130 file_(-1)
131 {
132 }
133
134 File(const char *path) :
135 file_(-1)
136 {
137 Open(path);
138 }
139
140 ~File() {
141 // XXX: this object is never deconstructed. if it were, this should unmap the memory
142 close(file_);
143 }
144
145 size_t Capacity() const {
146 return blocks_.size() * Block_;
147 }
148
149 void Open(const char *path) {
150 _assert(file_ == -1);
151 file_ = open(path, O_RDWR | O_CREAT | O_EXLOCK, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
152
153 struct stat stat;
154 fstat(file_, &stat);
155
156 size_t core(sizeof(Header) + sizeof(Base_));
157
158 size_t size(stat.st_size);
159 if (size == 0) {
160 Truncate_(core);
161 Header_().magic_ = Magic;
162 Size_() = core;
163 } else {
164 _assert(size >= core);
165 Truncate_(size);
166 _assert(Header_().magic_ == Magic);
167 _assert(Header_().version_ == 0);
168 }
169 }
170
171 void Reserve(size_t capacity) {
172 if (capacity <= Capacity())
173 return;
174 blocks_.pop_back();
175 Truncate_(capacity);
176 }
177
178 template <typename Target_>
179 Target_ &Get(uint32_t offset) {
180 return *reinterpret_cast<Target_ *>(blocks_[offset >> Shift_] + (offset & Mask_));
181 }
182
183 template <typename Target_>
184 Target_ &Get(Offset<Target_> &ref) {
185 return Get<Target_>(ref.GetOffset());
186 }
187
188 Base_ *operator ->() {
189 return &Get<Base_>(sizeof(Header));
190 }
191
192 template <typename Target_>
193 Offset<Target_> New(size_t extra = 0) {
194 size_t size(sizeof(Target_) + extra);
195 size = Round(size, sizeof(uintptr_t));
196 Reserve(Size_() + size);
197 uint32_t offset(Size_());
198 Size_() += size;
199 return Offset<Target_>(offset);
200 }
201 };
202
203 }
204
205 #endif//CYTORE_HPP