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
13namespace 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.
24template <class T>
25class ScopedPtr {
26 public:
27  ScopedPtr() : ptr_(NULL) {}
28  explicit ScopedPtr(T* ptr) : ptr_(ptr) {}
29  ~ScopedPtr() { Reset(NULL); }
30
31  T* Release() {
32    T* ret = ptr_;
33    ptr_ = NULL;
34    return ret;
35  }
36
37  void Reset(T* ptr) {
38    if (ptr_)
39      delete ptr_;
40    ptr_ = ptr;
41  }
42
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.
53const 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//
61class 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
71  const char* c_str() const { return ptr_; }
72  char* ptr() { return ptr_; }
73  size_t size() const { return size_; }
74  size_t capacity() const { return capacity_; }
75
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
116  void Assign(const String& other) { Assign(other.ptr_, other.size_); }
117
118  void Assign(const char* str) { Assign(str, strlen(str)); }
119
120  void Append(const char* str, size_t len);
121
122  void Append(const String& other) { Append(other.ptr_, other.size_); }
123
124  void Append(const char* str) { Append(str, strlen(str)); }
125
126 private:
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//
146template <class T>
147class Vector {
148 public:
149  Vector() : items_(0), count_(0), capacity_(0) {}
150  ~Vector() { free(items_); }
151
152  T& operator[](size_t index) { return items_[index]; }
153
154  bool IsEmpty() const { return count_ == 0; }
155
156  void PushBack(T item) { InsertAt(static_cast<int>(count_), item); }
157
158  T PopFirst() {
159    T result = items_[0];
160    RemoveAt(0);
161    return result;
162  }
163
164  T PopLast() {
165    T result = items_[count_ - 1];
166    Resize(count_ - 1);
167    return result;
168  }
169
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
182  bool Has(T item) const { return IndexOf(item) >= 0; }
183
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
196template <class T>
197int 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
205template <class T>
206void 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
222template <class T>
223void 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
235template <class T>
236void 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
243template <class T>
244void 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.
257template <class T>
258class Set {
259 public:
260  Set() : items_() {}
261  ~Set() {}
262
263  // Returns the number of items in the set.
264  size_t GetCount() const { return items_.GetCount(); }
265
266  bool IsEmpty() const { return items_.IsEmpty(); }
267
268  // Returns true iff the set contains a given 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
281template <class T>
282bool 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
291template <class T>
292bool 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