1 // Copyright Notice (GNU Affero GPL) {{{
2 /* Cyndir - (Awesome) Memory Mapped Dictionary
3 * Copyright (C) 2010 Jay Freeman (saurik)
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.
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.
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/>.
37 #define _assert(test) do \
39 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
46 static const uint32_t Magic = 'cynd';
58 template <typename Target_>
69 Offset(uint32_t offset) :
74 Offset &operator =(uint32_t offset) {
79 uint32_t GetOffset() const {
88 template <typename Type_>
89 static _finline Type_ Round(Type_ value, Type_ size) {
91 return value + mask & ~mask;
94 template <typename Base_>
97 static const unsigned Shift_ = 17;
98 static const size_t Block_ = 1 << Shift_;
99 static const size_t Mask_ = Block_ - 1;
103 std::vector<uint8_t *> blocks_;
106 return *reinterpret_cast<Header *>(blocks_[0]);
110 return Header_().size_;
113 void Map_(size_t size) {
114 size_t before(blocks_.size() * Block_);
115 size_t extend(size - before);
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);
122 void Truncate_(size_t capacity) {
123 capacity = Round(capacity, Block_);
124 ftruncate(file_, capacity);
134 File(const char *path) :
141 // XXX: this object is never deconstructed. if it were, this should unmap the memory
145 size_t Capacity() const {
146 return blocks_.size() * Block_;
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);
156 size_t core(sizeof(Header) + sizeof(Base_));
158 size_t size(stat.st_size);
161 Header_().magic_ = Magic;
164 _assert(size >= core);
166 _assert(Header_().magic_ == Magic);
167 _assert(Header_().version_ == 0);
171 void Reserve(size_t capacity) {
172 if (capacity <= Capacity())
178 template <typename Target_>
179 Target_ &Get(uint32_t offset) {
180 return *reinterpret_cast<Target_ *>(blocks_[offset >> Shift_] + (offset & Mask_));
183 template <typename Target_>
184 Target_ &Get(Offset<Target_> &ref) {
185 return Get<Target_>(ref.GetOffset());
188 Base_ *operator ->() {
189 return &Get<Base_>(sizeof(Header));
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_());
199 return Offset<Target_>(offset);