blob: 5cf20062805c681138a81d6addb6f3f5d7e82433 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRAZY_LINKER_UTIL_H
#define CRAZY_LINKER_UTIL_H
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
namespace crazy {
// Helper macro to loop around EINTR errors in syscalls.
#define HANDLE_EINTR(expr) TEMP_FAILURE_RETRY(expr)
// Helper macro to tag unused variables. Use in the declaration, between
// the type and name, as in:
// int CRAZY_UNUSED my_var = 0;
#define CRAZY_UNUSED __attribute__((unused))
// Offset in a file indicating a failure.
#define CRAZY_OFFSET_FAILED (-1)
// Helper scoped pointer class.
template <class T>
class ScopedPtr {
public:
ScopedPtr() : ptr_(NULL) {}
explicit ScopedPtr(T* ptr) : ptr_(ptr) {}
~ScopedPtr() { Reset(NULL); }
T* Release() {
T* ret = ptr_;
ptr_ = NULL;
return ret;
}
void Reset(T* ptr) {
if (ptr_)
delete ptr_;
ptr_ = ptr;
}
T* Get() { return ptr_; }
T& operator*() { return *ptr_; }
T* operator->() { return ptr_; }
private:
T* ptr_;
};
// Return the base name from a file path. Important: this is a pointer
// into the original string.
const char* GetBaseNamePtr(const char* path);
// Helper class used to implement a string. Similar to std::string
// without all the crazy iterator / iostream stuff.
//
// Required because crazy linker should only link against the system
// libstdc++ that only provides new/delete.
//
class String {
public:
String();
String(const char* str, size_t len);
String(const String& other);
explicit String(const char* str);
explicit String(char ch);
~String();
const char* c_str() const { return ptr_; }
char* ptr() { return ptr_; }
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
bool IsEmpty() const { return size_ == 0; }
char& operator[](size_t index) { return ptr_[index]; }
String& operator=(const String& other) {
Assign(other.ptr_, other.size_);
return *this;
}
String& operator=(const char* str) {
Assign(str, strlen(str));
return *this;
}
String& operator=(char ch) {
Assign(&ch, 1);
return *this;
}
String& operator+=(const String& other) {
Append(other);
return *this;
}
String& operator+=(const char* str) {
Append(str, strlen(str));
return *this;
}
String& operator+=(char ch) {
Append(&ch, 1);
return *this;
}
void Resize(size_t new_size);
void Reserve(size_t new_capacity);
void Assign(const char* str, size_t len);
void Assign(const String& other) { Assign(other.ptr_, other.size_); }
void Assign(const char* str) { Assign(str, strlen(str)); }
void Append(const char* str, size_t len);
void Append(const String& other) { Append(other.ptr_, other.size_); }
void Append(const char* str) { Append(str, strlen(str)); }
private:
void Init(void) {
ptr_ = const_cast<char*>(kEmpty);
size_ = 0;
capacity_ = 0;
}
static const char kEmpty[];
char* ptr_;
size_t size_;
size_t capacity_;
};
// Helper template used to implement a simple vector or POD-struct items.
// I.e. this uses memmove() to move items during insertion / removal.
//
// Required because crazy linker should only link against the system
// libstdc++ which only provides new/delete.
//
template <class T>
class Vector {
public:
Vector() : items_(0), count_(0), capacity_(0) {}
~Vector() { free(items_); }
T& operator[](size_t index) { return items_[index]; }
bool IsEmpty() const { return count_ == 0; }
void PushBack(T item) { InsertAt(static_cast<int>(count_), item); }
T PopFirst() {
T result = items_[0];
RemoveAt(0);
return result;
}
T PopLast() {
T result = items_[count_ - 1];
Resize(count_ - 1);
return result;
}
void Remove(T item) {
int index = IndexOf(item);
if (index >= 0)
RemoveAt(index);
}
void InsertAt(int index, T item);
void RemoveAt(int index);
int IndexOf(T item) const;
bool Has(T item) const { return IndexOf(item) >= 0; }
size_t GetCount() const { return count_; }
void Reserve(size_t new_capacity);
void Resize(size_t new_count);
private:
T* items_;
size_t count_;
size_t capacity_;
};
template <class T>
int Vector<T>::IndexOf(T item) const {
for (size_t n = 0; n < count_; ++n) {
if (items_[n] == item)
return static_cast<int>(n);
}
return -1;
}
template <class T>
void Vector<T>::InsertAt(int index, T item) {
if (count_ >= capacity_)
Reserve(capacity_ + (capacity_ >> 1) + 4);
if (index < 0)
index = 0;
size_t n = static_cast<size_t>(index);
if (n > count_)
n = count_;
else
memmove(items_ + n + 1, items_ + n, (count_ - n) * sizeof(T));
items_[n] = item;
count_++;
}
template <class T>
void Vector<T>::RemoveAt(int index) {
if (index < 0)
return;
size_t n = static_cast<size_t>(index);
if (n >= count_)
return;
memmove(items_ + n, items_ + n + 1, (count_ - n - 1) * sizeof(T));
count_--;
}
template <class T>
void Vector<T>::Reserve(size_t new_capacity) {
items_ = reinterpret_cast<T*>(realloc(items_, new_capacity * sizeof(T)));
capacity_ = new_capacity;
if (count_ > capacity_)
count_ = capacity_;
}
template <class T>
void Vector<T>::Resize(size_t new_size) {
if (new_size > capacity_)
Reserve(new_size);
if (new_size > count_)
memset(items_ + count_, 0, (new_size - count_) * sizeof(T));
count_ = new_size;
}
// Helper template class to implement a set.
// Given that the crazy linker doesn't expect to deal with hundreds
// of libraries at the same time, implement it with a vector.
template <class T>
class Set {
public:
Set() : items_() {}
~Set() {}
// Returns the number of items in the set.
size_t GetCount() const { return items_.GetCount(); }
bool IsEmpty() const { return items_.IsEmpty(); }
// Returns true iff the set contains a given item.
bool Has(T item) const { return items_.Has(item); }
// Add an item to the set. Returns false iff the item was already in it.
bool Add(T item);
// Delete an item from the set. Returns false iff the item was not in it.
bool Del(T item);
private:
Vector<T> items_;
};
template <class T>
bool Set<T>::Add(T item) {
int idx = items_.IndexOf(item);
if (idx >= 0)
return false;
items_.PushBack(item);
return true;
}
template <class T>
bool Set<T>::Del(T item) {
int idx = items_.IndexOf(item);
if (idx < 0)
return false;
items_.RemoveAt(idx);
return true;
}
} // namespace crazy
#endif // CRAZY_LINKER_UTIL_H