mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-27 11:00:47 +00:00
3016e595f0
byuu says: New terminal is in. Much nicer to use now. Command history makes a major difference in usability. The SMP is now fully traceable and debuggable. Basically they act as separate entities, you can trace both at the same time, but for the most part running and stepping is performed on the chip you select. I'm going to put off CPU+SMP interleave support for a while. I don't actually think it'll be too hard. Will get trickier if/when we support coprocessor debugging. Remaining tasks: - aliases - hotkeys - save states - window geometry Basically, the debugger's done. Just have to add the UI fluff. I also removed tracing/memory export from higan. It was always meant to be temporary until the debugger was remade.
277 lines
7.2 KiB
C++
277 lines
7.2 KiB
C++
#ifndef NALL_VECTOR_HPP
|
|
#define NALL_VECTOR_HPP
|
|
|
|
#include <algorithm>
|
|
#include <initializer_list>
|
|
#include <new>
|
|
#include <utility>
|
|
#include <nall/algorithm.hpp>
|
|
#include <nall/bit.hpp>
|
|
#include <nall/maybe.hpp>
|
|
#include <nall/sort.hpp>
|
|
#include <nall/utility.hpp>
|
|
|
|
namespace nall {
|
|
|
|
template<typename T> struct vector {
|
|
struct exception_out_of_bounds{};
|
|
|
|
protected:
|
|
T* pool = nullptr;
|
|
unsigned poolbase = 0;
|
|
unsigned poolsize = 0;
|
|
unsigned objectsize = 0;
|
|
|
|
public:
|
|
explicit operator bool() const { return objectsize; }
|
|
T* data() { return pool + poolbase; }
|
|
const T* data() const { return pool + poolbase; }
|
|
|
|
bool empty() const { return objectsize == 0; }
|
|
unsigned size() const { return objectsize; }
|
|
unsigned capacity() const { return poolsize; }
|
|
|
|
T* move() {
|
|
T* result = pool + poolbase;
|
|
pool = nullptr;
|
|
poolbase = 0;
|
|
poolsize = 0;
|
|
objectsize = 0;
|
|
return result;
|
|
}
|
|
|
|
void reset() {
|
|
if(pool) {
|
|
for(unsigned n = 0; n < objectsize; n++) pool[poolbase + n].~T();
|
|
free(pool);
|
|
}
|
|
pool = nullptr;
|
|
poolbase = 0;
|
|
poolsize = 0;
|
|
objectsize = 0;
|
|
}
|
|
|
|
void reserve(unsigned size) {
|
|
if(size <= poolsize) return;
|
|
size = bit::round(size); //amortize growth
|
|
|
|
T* copy = (T*)calloc(size, sizeof(T));
|
|
for(unsigned n = 0; n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
|
free(pool);
|
|
pool = copy;
|
|
poolbase = 0;
|
|
poolsize = size;
|
|
}
|
|
|
|
void resize(unsigned size) {
|
|
T* copy = (T*)calloc(size, sizeof(T));
|
|
for(unsigned n = 0; n < size && n < objectsize; n++) new(copy + n) T(std::move(pool[poolbase + n]));
|
|
reset();
|
|
pool = copy;
|
|
poolbase = 0;
|
|
poolsize = size;
|
|
objectsize = size;
|
|
}
|
|
|
|
template<typename... Args> void prepend(const T& data, Args&&... args) {
|
|
prepend(std::forward<Args>(args)...);
|
|
prepend(data);
|
|
}
|
|
|
|
T& prepend(const T& data) {
|
|
reserve(objectsize + 1);
|
|
if(poolbase == 0) {
|
|
unsigned available = poolsize - objectsize;
|
|
poolbase = max(1u, available >> 1);
|
|
for(signed n = objectsize - 1; n >= 0; n--) {
|
|
pool[poolbase + n] = std::move(pool[n]);
|
|
}
|
|
}
|
|
new(pool + --poolbase) T(data);
|
|
objectsize++;
|
|
return first();
|
|
}
|
|
|
|
template<typename... Args> void append(const T& data, Args&&... args) {
|
|
append(data);
|
|
append(std::forward<Args>(args)...);
|
|
}
|
|
|
|
T& append(const T& data) {
|
|
reserve(poolbase + objectsize + 1);
|
|
new(pool + poolbase + objectsize++) T(data);
|
|
return last();
|
|
}
|
|
|
|
bool appendOnce(const T& data) {
|
|
if(find(data)) return false;
|
|
return append(data), true;
|
|
}
|
|
|
|
void insert(unsigned position, const T& data) {
|
|
if(position == 0) return prepend(data);
|
|
append(data);
|
|
if(position == ~0u) return;
|
|
for(signed n = objectsize - 1; n > position; n--) {
|
|
pool[poolbase + n] = std::move(pool[poolbase + n - 1]);
|
|
}
|
|
pool[poolbase + position] = data;
|
|
}
|
|
|
|
void remove(unsigned position = ~0u, unsigned length = 1) {
|
|
if(position == ~0u) position = objectsize - 1;
|
|
if(position + length > objectsize) throw exception_out_of_bounds{};
|
|
|
|
if(position == 0) {
|
|
for(unsigned n = 0; n < length; n++) pool[poolbase + n].~T();
|
|
poolbase += length;
|
|
} else {
|
|
for(unsigned n = position; n < objectsize; n++) {
|
|
if(n + length < objectsize) {
|
|
pool[poolbase + n] = std::move(pool[poolbase + n + length]);
|
|
} else {
|
|
pool[poolbase + n].~T();
|
|
}
|
|
}
|
|
}
|
|
objectsize -= length;
|
|
}
|
|
|
|
void removeFirst() { return remove(0); }
|
|
void removeLast() { return remove(~0u); }
|
|
|
|
T take(unsigned position = ~0u) {
|
|
if(position == ~0u) position = objectsize - 1;
|
|
T object = pool[poolbase + position];
|
|
remove(position);
|
|
return object;
|
|
}
|
|
|
|
T takeFirst() { return take(0); }
|
|
T takeLast() { return take(~0u); }
|
|
|
|
void reverse() {
|
|
unsigned pivot = size() / 2;
|
|
for(unsigned l = 0, r = size() - 1; l < pivot; l++, r--) {
|
|
std::swap(pool[poolbase + l], pool[poolbase + r]);
|
|
}
|
|
}
|
|
|
|
void sort() {
|
|
nall::sort(pool + poolbase, objectsize);
|
|
}
|
|
|
|
template<typename Comparator> void sort(const Comparator &lessthan) {
|
|
nall::sort(pool + poolbase, objectsize, lessthan);
|
|
}
|
|
|
|
maybe<unsigned> find(const T& data) {
|
|
for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n;
|
|
return nothing;
|
|
}
|
|
|
|
T& first() {
|
|
if(objectsize == 0) throw exception_out_of_bounds();
|
|
return pool[poolbase];
|
|
}
|
|
|
|
const T& first() const {
|
|
if(objectsize == 0) throw exception_out_of_bounds();
|
|
return pool[poolbase];
|
|
}
|
|
|
|
T& last() {
|
|
if(objectsize == 0) throw exception_out_of_bounds();
|
|
return pool[poolbase + objectsize - 1];
|
|
}
|
|
|
|
const T& last() const {
|
|
if(objectsize == 0) throw exception_out_of_bounds();
|
|
return pool[poolbase + objectsize - 1];
|
|
}
|
|
|
|
//access
|
|
inline T& operator[](unsigned position) {
|
|
if(position >= objectsize) throw exception_out_of_bounds();
|
|
return pool[poolbase + position];
|
|
}
|
|
|
|
inline const T& operator[](unsigned position) const {
|
|
if(position >= objectsize) throw exception_out_of_bounds();
|
|
return pool[poolbase + position];
|
|
}
|
|
|
|
inline T& operator()(unsigned position) {
|
|
if(position >= poolsize) reserve(position + 1);
|
|
while(position >= objectsize) append(T());
|
|
return pool[poolbase + position];
|
|
}
|
|
|
|
inline const T& operator()(unsigned position, const T& data) const {
|
|
if(position >= objectsize) return data;
|
|
return pool[poolbase + position];
|
|
}
|
|
|
|
//iteration
|
|
struct iterator {
|
|
T& operator*() { return source.operator[](position); }
|
|
bool operator!=(const iterator& source) const { return position != source.position; }
|
|
iterator& operator++() { position++; return *this; }
|
|
iterator(vector& source, unsigned position) : source(source), position(position) {}
|
|
|
|
private:
|
|
vector& source;
|
|
unsigned position;
|
|
};
|
|
|
|
iterator begin() { return iterator(*this, 0); }
|
|
iterator end() { return iterator(*this, size()); }
|
|
|
|
struct constIterator {
|
|
const T& operator*() const { return source.operator[](position); }
|
|
bool operator!=(const constIterator& source) const { return position != source.position; }
|
|
constIterator& operator++() { position++; return *this; }
|
|
constIterator(const vector& source, unsigned position) : source(source), position(position) {}
|
|
|
|
private:
|
|
const vector& source;
|
|
unsigned position;
|
|
};
|
|
|
|
const constIterator begin() const { return constIterator(*this, 0); }
|
|
const constIterator end() const { return constIterator(*this, size()); }
|
|
|
|
//copy
|
|
inline vector& operator=(const vector& source) {
|
|
reset();
|
|
reserve(source.size());
|
|
for(auto& data : source) append(data);
|
|
return *this;
|
|
}
|
|
|
|
//move
|
|
inline vector& operator=(vector&& source) {
|
|
reset();
|
|
pool = source.pool;
|
|
poolbase = source.poolbase;
|
|
poolsize = source.poolsize;
|
|
objectsize = source.objectsize;
|
|
source.pool = nullptr;
|
|
source.poolbase = 0;
|
|
source.poolsize = 0;
|
|
source.objectsize = 0;
|
|
return *this;
|
|
}
|
|
|
|
//construction and destruction
|
|
vector() = default;
|
|
vector(std::initializer_list<T> list) { for(auto& data : list) append(data); }
|
|
vector(const vector& source) { operator=(source); }
|
|
vector(vector&& source) { operator=(std::move(source)); }
|
|
~vector() { reset(); }
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|