1 // Copyright (c) 2013 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