1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef CRAZY_LINKER_UTIL_H
6 #define CRAZY_LINKER_UTIL_H
7
8 #include <fcntl.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <unistd.h>
12
13 namespace crazy {
14
15 // Helper macro to loop around EINTR errors in syscalls.
16 #define HANDLE_EINTR(expr) TEMP_FAILURE_RETRY(expr)
17
18 // Helper macro to tag unused variables. Use in the declaration, between
19 // the type and name, as in:
20 // int CRAZY_UNUSED my_var = 0;
21 #define CRAZY_UNUSED __attribute__((unused))
22
23 // Helper scoped pointer class.
24 template <class T>
25 class ScopedPtr {
26 public:
ScopedPtr()27 ScopedPtr() : ptr_(NULL) {}
ScopedPtr(T * ptr)28 explicit ScopedPtr(T* ptr) : ptr_(ptr) {}
~ScopedPtr()29 ~ScopedPtr() { Reset(NULL); }
30
Release()31 T* Release() {
32 T* ret = ptr_;
33 ptr_ = NULL;
34 return ret;
35 }
36
Reset(T * ptr)37 void Reset(T* ptr) {
38 if (ptr_)
39 delete ptr_;
40 ptr_ = ptr;
41 }
42
Get()43 T* Get() { return ptr_; }
44 T& operator*() { return *ptr_; }
45 T* operator->() { return ptr_; }
46
47 private:
48 T* ptr_;
49 };
50
51 // Return the base name from a file path. Important: this is a pointer
52 // into the original string.
53 const char* GetBaseNamePtr(const char* path);
54
55 // Helper class used to implement a string. Similar to std::string
56 // without all the crazy iterator / iostream stuff.
57 //
58 // Required because crazy linker should only link against the system
59 // libstdc++ that only provides new/delete.
60 //
61 class String {
62 public:
63 String();
64 String(const char* str, size_t len);
65 String(const String& other);
66 explicit String(const char* str);
67 explicit String(char ch);
68
69 ~String();
70
c_str()71 const char* c_str() const { return ptr_; }
ptr()72 char* ptr() { return ptr_; }
size()73 size_t size() const { return size_; }
capacity()74 size_t capacity() const { return capacity_; }
75
IsEmpty()76 bool IsEmpty() const { return size_ == 0; }
77
78 char& operator[](size_t index) { return ptr_[index]; }
79
80 String& operator=(const String& other) {
81 Assign(other.ptr_, other.size_);
82 return *this;
83 }
84
85 String& operator=(const char* str) {
86 Assign(str, strlen(str));
87 return *this;
88 }
89
90 String& operator=(char ch) {
91 Assign(&ch, 1);
92 return *this;
93 }
94
95 String& operator+=(const String& other) {
96 Append(other);
97 return *this;
98 }
99
100 String& operator+=(const char* str) {
101 Append(str, strlen(str));
102 return *this;
103 }
104
105 String& operator+=(char ch) {
106 Append(&ch, 1);
107 return *this;
108 }
109
110 void Resize(size_t new_size);
111
112 void Reserve(size_t new_capacity);
113
114 void Assign(const char* str, size_t len);
115
Assign(const String & other)116 void Assign(const String& other) { Assign(other.ptr_, other.size_); }
117
Assign(const char * str)118 void Assign(const char* str) { Assign(str, strlen(str)); }
119
120 void Append(const char* str, size_t len);
121
Append(const String & other)122 void Append(const String& other) { Append(other.ptr_, other.size_); }
123
Append(const char * str)124 void Append(const char* str) { Append(str, strlen(str)); }
125
126 private:
Init(void)127 void Init(void) {
128 ptr_ = const_cast<char*>(kEmpty);
129 size_ = 0;
130 capacity_ = 0;
131 }
132
133 static const char kEmpty[];
134
135 char* ptr_;
136 size_t size_;
137 size_t capacity_;
138 };
139
140 // Helper template used to implement a simple vector or POD-struct items.
141 // I.e. this uses memmove() to move items during insertion / removal.
142 //
143 // Required because crazy linker should only link against the system
144 // libstdc++ which only provides new/delete.
145 //
146 template <class T>
147 class Vector {
148 public:
Vector()149 Vector() : items_(0), count_(0), capacity_(0) {}
~Vector()150 ~Vector() { free(items_); }
151
152 T& operator[](size_t index) { return items_[index]; }
153
IsEmpty()154 bool IsEmpty() const { return count_ == 0; }
155
PushBack(T item)156 void PushBack(T item) { InsertAt(static_cast<int>(count_), item); }
157
PopFirst()158 T PopFirst() {
159 T result = items_[0];
160 RemoveAt(0);
161 return result;
162 }
163
PopLast()164 T PopLast() {
165 T result = items_[count_ - 1];
166 Resize(count_ - 1);
167 return result;
168 }
169
Remove(T item)170 void Remove(T item) {
171 int index = IndexOf(item);
172 if (index >= 0)
173 RemoveAt(index);
174 }
175
176 void InsertAt(int index, T item);
177
178 void RemoveAt(int index);
179
180 int IndexOf(T item) const;
181
Has(T item)182 bool Has(T item) const { return IndexOf(item) >= 0; }
183
GetCount()184 size_t GetCount() const { return count_; }
185
186 void Reserve(size_t new_capacity);
187
188 void Resize(size_t new_count);
189
190 private:
191 T* items_;
192 size_t count_;
193 size_t capacity_;
194 };
195
196 template <class T>
IndexOf(T item)197 int Vector<T>::IndexOf(T item) const {
198 for (size_t n = 0; n < count_; ++n) {
199 if (items_[n] == item)
200 return static_cast<int>(n);
201 }
202 return -1;
203 }
204
205 template <class T>
InsertAt(int index,T item)206 void Vector<T>::InsertAt(int index, T item) {
207 if (count_ >= capacity_)
208 Reserve(capacity_ + (capacity_ >> 1) + 4);
209
210 if (index < 0)
211 index = 0;
212 size_t n = static_cast<size_t>(index);
213 if (n > count_)
214 n = count_;
215 else
216 memmove(items_ + n + 1, items_ + n, (count_ - n) * sizeof(T));
217
218 items_[n] = item;
219 count_++;
220 }
221
222 template <class T>
RemoveAt(int index)223 void Vector<T>::RemoveAt(int index) {
224 if (index < 0)
225 return;
226
227 size_t n = static_cast<size_t>(index);
228 if (n >= count_)
229 return;
230
231 memmove(items_ + n, items_ + n + 1, (count_ - n - 1) * sizeof(T));
232 count_--;
233 }
234
235 template <class T>
Reserve(size_t new_capacity)236 void Vector<T>::Reserve(size_t new_capacity) {
237 items_ = reinterpret_cast<T*>(realloc(items_, new_capacity * sizeof(T)));
238 capacity_ = new_capacity;
239 if (count_ > capacity_)
240 count_ = capacity_;
241 }
242
243 template <class T>
Resize(size_t new_size)244 void Vector<T>::Resize(size_t new_size) {
245 if (new_size > capacity_)
246 Reserve(new_size);
247
248 if (new_size > count_)
249 memset(items_ + count_, 0, (new_size - count_) * sizeof(T));
250
251 count_ = new_size;
252 }
253
254 // Helper template class to implement a set.
255 // Given that the crazy linker doesn't expect to deal with hundreds
256 // of libraries at the same time, implement it with a vector.
257 template <class T>
258 class Set {
259 public:
Set()260 Set() : items_() {}
~Set()261 ~Set() {}
262
263 // Returns the number of items in the set.
GetCount()264 size_t GetCount() const { return items_.GetCount(); }
265
IsEmpty()266 bool IsEmpty() const { return items_.IsEmpty(); }
267
268 // Returns true iff the set contains a given item.
Has(T item)269 bool Has(T item) const { return items_.Has(item); }
270
271 // Add an item to the set. Returns false iff the item was already in it.
272 bool Add(T item);
273
274 // Delete an item from the set. Returns false iff the item was not in it.
275 bool Del(T item);
276
277 private:
278 Vector<T> items_;
279 };
280
281 template <class T>
Add(T item)282 bool Set<T>::Add(T item) {
283 int idx = items_.IndexOf(item);
284 if (idx >= 0)
285 return false;
286
287 items_.PushBack(item);
288 return true;
289 }
290
291 template <class T>
Del(T item)292 bool Set<T>::Del(T item) {
293 int idx = items_.IndexOf(item);
294 if (idx < 0)
295 return false;
296 items_.RemoveAt(idx);
297 return true;
298 }
299
300 } // namespace crazy
301
302 #endif // CRAZY_LINKER_UTIL_H
303