Moving some util types into poly.

This commit is contained in:
Ben Vanik
2015-03-22 22:12:37 -07:00
parent b392afbfae
commit 59395318f3
54 changed files with 280 additions and 242 deletions

103
src/poly/arena.cc Normal file
View File

@@ -0,0 +1,103 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "poly/arena.h"
#include <memory>
#include "poly/assert.h"
namespace poly {
Arena::Arena(size_t chunk_size)
: chunk_size_(chunk_size), head_chunk_(nullptr), active_chunk_(nullptr) {}
Arena::~Arena() {
Reset();
Chunk* chunk = head_chunk_;
while (chunk) {
Chunk* next = chunk->next;
delete chunk;
chunk = next;
}
head_chunk_ = nullptr;
}
void Arena::Reset() {
active_chunk_ = head_chunk_;
if (active_chunk_) {
active_chunk_->offset = 0;
}
}
void Arena::DebugFill() {
auto chunk = head_chunk_;
while (chunk) {
std::memset(chunk->buffer, 0xCD, chunk->capacity);
chunk = chunk->next;
}
}
void* Arena::Alloc(size_t size) {
if (active_chunk_) {
if (active_chunk_->capacity - active_chunk_->offset < size + 4096) {
Chunk* next = active_chunk_->next;
if (!next) {
assert_true(size < chunk_size_, "need to support larger chunks");
next = new Chunk(chunk_size_);
active_chunk_->next = next;
}
next->offset = 0;
active_chunk_ = next;
}
} else {
head_chunk_ = active_chunk_ = new Chunk(chunk_size_);
}
uint8_t* p = active_chunk_->buffer + active_chunk_->offset;
active_chunk_->offset += size;
return p;
}
void* Arena::CloneContents() {
size_t total_length = 0;
Chunk* chunk = head_chunk_;
while (chunk) {
total_length += chunk->offset;
if (chunk == active_chunk_) {
break;
}
chunk = chunk->next;
}
void* result = malloc(total_length);
uint8_t* p = (uint8_t*)result;
chunk = head_chunk_;
while (chunk) {
std::memcpy(p, chunk->buffer, chunk->offset);
p += chunk->offset;
if (chunk == active_chunk_) {
break;
}
chunk = chunk->next;
}
return result;
}
Arena::Chunk::Chunk(size_t chunk_size)
: next(nullptr), capacity(chunk_size), buffer(0), offset(0) {
buffer = reinterpret_cast<uint8_t*>(malloc(capacity));
}
Arena::Chunk::~Chunk() {
if (buffer) {
free(buffer);
}
}
} // namespace poly

55
src/poly/arena.h Normal file
View File

@@ -0,0 +1,55 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef POLY_ARENA_H_
#define POLY_ARENA_H_
#include <cstddef>
#include <cstdint>
namespace poly {
class Arena {
public:
Arena(size_t chunk_size = 4 * 1024 * 1024);
~Arena();
void Reset();
void DebugFill();
void* Alloc(size_t size);
template <typename T>
T* Alloc() {
return reinterpret_cast<T*>(Alloc(sizeof(T)));
}
void* CloneContents();
private:
class Chunk {
public:
Chunk(size_t chunk_size);
~Chunk();
Chunk* next;
size_t capacity;
uint8_t* buffer;
size_t offset;
};
private:
size_t chunk_size_;
Chunk* head_chunk_;
Chunk* active_chunk_;
};
} // namespace poly
#endif // POLY_ARENA_H_

View File

@@ -23,6 +23,7 @@
#include "poly/platform.h"
#include "poly/string.h"
#include "poly/threading.h"
#include "poly/vec128.h"
namespace poly {} // namespace poly

43
src/poly/reset_scope.h Normal file
View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef POLY_RESET_SCOPE_H_
#define POLY_RESET_SCOPE_H_
#include <mutex>
namespace poly {
template <typename T>
class ResetScope {
public:
ResetScope(T* value) : value_(value) {}
~ResetScope() {
if (value_) {
value_->Reset();
}
}
private:
T* value_;
};
template <typename T>
inline ResetScope<T> make_reset_scope(T* value) {
return ResetScope<T>(value);
}
template <typename T>
inline ResetScope<T> make_reset_scope(const std::unique_ptr<T>& value) {
return ResetScope<T>(value.get());
}
} // namespace poly
#endif // POLY_RESET_SCOPE_H_

View File

@@ -1,6 +1,8 @@
# Copyright 2014 Ben Vanik. All Rights Reserved.
{
'sources': [
'arena.cc',
'arena.h',
'assert.h',
'atomic.h',
'byte_order.h',
@@ -20,10 +22,15 @@
'memory.h',
'platform.h',
'poly.h',
'reset_scope.h',
'string.cc',
'string.h',
'string_buffer.cc',
'string_buffer.h',
'threading.cc',
'threading.h',
'type_pool.h',
'vec128.h',
],
'conditions': [

71
src/poly/string_buffer.cc Normal file
View File

@@ -0,0 +1,71 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "poly/string_buffer.h"
#include <algorithm>
#include <cstdarg>
namespace poly {
StringBuffer::StringBuffer(size_t initial_capacity) {
buffer_.reserve(std::max(initial_capacity, static_cast<size_t>(1024)));
}
StringBuffer::~StringBuffer() = default;
void StringBuffer::Reset() { buffer_.resize(0); }
void StringBuffer::Grow(size_t additional_length) {
size_t old_capacity = buffer_.capacity();
if (buffer_.size() + additional_length <= old_capacity) {
return;
}
size_t new_capacity =
std::max(buffer_.size() + additional_length, old_capacity * 2);
buffer_.reserve(new_capacity);
}
void StringBuffer::Append(const std::string& value) {
AppendBytes(reinterpret_cast<const uint8_t*>(value.data()), value.size());
}
void StringBuffer::Append(const char* format, ...) {
va_list args;
va_start(args, format);
AppendVarargs(format, args);
va_end(args);
}
void StringBuffer::AppendVarargs(const char* format, va_list args) {
int length = vsnprintf(nullptr, 0, format, args);
auto offset = buffer_.size();
Grow(length + 1);
buffer_.resize(buffer_.size() + length);
vsnprintf(buffer_.data() + offset, buffer_.capacity(), format, args);
buffer_[buffer_.size()] = 0;
}
void StringBuffer::AppendBytes(const uint8_t* buffer, size_t length) {
auto offset = buffer_.size();
Grow(length + 1);
buffer_.resize(buffer_.size() + length);
memcpy(buffer_.data() + offset, buffer, length);
buffer_[buffer_.size()] = 0;
}
const char* StringBuffer::GetString() const { return buffer_.data(); }
std::string StringBuffer::to_string() {
return std::string(buffer_.data(), buffer_.size());
}
char* StringBuffer::ToString() { return strdup(buffer_.data()); }
} // namespace poly

46
src/poly/string_buffer.h Normal file
View File

@@ -0,0 +1,46 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef POLY_STRING_BUFFER_H_
#define POLY_STRING_BUFFER_H_
#include <cstdint>
#include <string>
#include <vector>
namespace poly {
class StringBuffer {
public:
StringBuffer(size_t initial_capacity = 0);
~StringBuffer();
size_t length() const { return buffer_.size(); }
void Reset();
void Append(const std::string& value);
void Append(const char* format, ...);
void AppendVarargs(const char* format, va_list args);
void AppendBytes(const uint8_t* buffer, size_t length);
const char* GetString() const;
std::string to_string();
char* ToString();
char* EncodeBase64();
private:
void Grow(size_t additional_length);
std::vector<char> buffer_;
};
} // namespace poly
#endif // POLY_STRING_BUFFER_H_

59
src/poly/type_pool.h Normal file
View File

@@ -0,0 +1,59 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef POLY_TYPE_POOL_H_
#define POLY_TYPE_POOL_H_
#include <mutex>
#include <vector>
namespace poly {
template <class T, typename A>
class TypePool {
public:
~TypePool() { Reset(); }
void Reset() {
std::lock_guard<std::mutex> guard(lock_);
for (auto it = list_.begin(); it != list_.end(); ++it) {
T* value = *it;
delete value;
}
list_.clear();
}
T* Allocate(A arg0) {
T* result = 0;
{
std::lock_guard<std::mutex> guard(lock_);
if (list_.size()) {
result = list_.back();
list_.pop_back();
}
}
if (!result) {
result = new T(arg0);
}
return result;
}
void Release(T* value) {
std::lock_guard<std::mutex> guard(lock_);
list_.push_back(value);
}
private:
std::mutex lock_;
std::vector<T*> list_;
};
} // namespace poly
#endif // POLY_TYPE_POOL_H_

196
src/poly/vec128.h Normal file
View File

@@ -0,0 +1,196 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef POLY_VEC128_H_
#define POLY_VEC128_H_
#include <cstddef>
namespace poly {
// The first rule of vector programming is to only rely on exact positions
// when absolutely required - prefer dumb loops to exact offsets.
// Vectors in memory are laid out as in AVX registers on little endian
// machines. Note that little endian is dumb, so the byte at index 0 in
// the vector is is really byte 15 (or the high byte of short 7 or int 3).
// Because of this, all byte access should be via the accessors instead of
// the direct array.
// Altivec big endian layout: AVX little endian layout:
// +---------+---------+---------+ +---------+---------+---------+
// | int32 0 | int16 0 | int8 0 | | int32 3 | int16 7 | int8 15 |
// | | +---------+ | | +---------+
// | | | int8 1 | | | | int8 14 |
// | +---------+---------+ | +---------+---------+
// | | int16 1 | int8 2 | | | int16 6 | int8 13 |
// | | +---------+ | | +---------+
// | | | int8 3 | | | | int8 12 |
// +---------+---------+---------+ +---------+---------+---------+
// | int32 1 | int16 2 | int8 4 | | int32 2 | int16 5 | int8 11 |
// | | +---------+ | | +---------+
// | | | int8 5 | | | | int8 10 |
// | +---------+---------+ | +---------+---------+
// | | int16 3 | int8 6 | | | int16 4 | int8 9 |
// | | +---------+ | | +---------+
// | | | int8 7 | | | | int8 8 |
// +---------+---------+---------+ +---------+---------+---------+
// | int32 2 | int16 4 | int8 8 | | int32 1 | int16 3 | int8 7 |
// | | +---------+ | | +---------+
// | | | int8 9 | | | | int8 6 |
// | +---------+---------+ | +---------+---------+
// | | int16 5 | int8 10 | | | int16 2 | int8 5 |
// | | +---------+ | | +---------+
// | | | int8 11 | | | | int8 4 |
// +---------+---------+---------+ +---------+---------+---------+
// | int32 3 | int16 6 | int8 12 | | int32 0 | int16 1 | int8 3 |
// | | +---------+ | | +---------+
// | | | int8 13 | | | | int8 2 |
// | +---------+---------+ | +---------+---------+
// | | int16 7 | int8 14 | | | int16 0 | int8 1 |
// | | +---------+ | | +---------+
// | | | int8 15 | | | | int8 0 |
// +---------+---------+---------+ +---------+---------+---------+
//
// Logical order:
// +-----+-----+-----+-----+ +-----+-----+-----+-----+
// | X | Y | Z | W | | W | Z | Y | X |
// +-----+-----+-----+-----+ +-----+-----+-----+-----+
//
// Mapping indices is easy:
// int32[i ^ 0x3]
// int16[i ^ 0x7]
// int8[i ^ 0xF]
typedef struct alignas(16) vec128_s {
union {
struct {
float x;
float y;
float z;
float w;
};
struct {
int32_t ix;
int32_t iy;
int32_t iz;
int32_t iw;
};
struct {
uint32_t ux;
uint32_t uy;
uint32_t uz;
uint32_t uw;
};
float f32[4];
int8_t i8[16];
uint8_t u8[16];
int16_t i16[8];
uint16_t u16[8];
int32_t i32[4];
uint32_t u32[4];
int64_t i64[2];
uint64_t u64[2];
struct {
uint64_t low;
uint64_t high;
};
};
bool operator==(const vec128_s& b) const {
return low == b.low && high == b.high;
}
bool operator!=(const vec128_s& b) const {
return low != b.low || high != b.high;
}
} vec128_t;
static inline vec128_t vec128i(uint32_t src) {
vec128_t v;
for (auto i = 0; i < 4; ++i) {
v.u32[i] = src;
}
return v;
}
static inline vec128_t vec128i(uint32_t x, uint32_t y, uint32_t z, uint32_t w) {
vec128_t v;
v.u32[0] = x;
v.u32[1] = y;
v.u32[2] = z;
v.u32[3] = w;
return v;
}
static inline vec128_t vec128f(float src) {
vec128_t v;
for (auto i = 0; i < 4; ++i) {
v.f32[i] = src;
}
return v;
}
static inline vec128_t vec128f(float x, float y, float z, float w) {
vec128_t v;
v.f32[0] = x;
v.f32[1] = y;
v.f32[2] = z;
v.f32[3] = w;
return v;
}
static inline vec128_t vec128s(uint16_t src) {
vec128_t v;
for (auto i = 0; i < 8; ++i) {
v.u16[i] = src;
}
return v;
}
static inline vec128_t vec128s(uint16_t x0, uint16_t x1, uint16_t y0,
uint16_t y1, uint16_t z0, uint16_t z1,
uint16_t w0, uint16_t w1) {
vec128_t v;
v.u16[0] = x1;
v.u16[1] = x0;
v.u16[2] = y1;
v.u16[3] = y0;
v.u16[4] = z1;
v.u16[5] = z0;
v.u16[6] = w1;
v.u16[7] = w0;
return v;
}
static inline vec128_t vec128b(uint8_t src) {
vec128_t v;
for (auto i = 0; i < 16; ++i) {
v.u8[i] = src;
}
return v;
}
static inline vec128_t vec128b(uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3,
uint8_t y0, uint8_t y1, uint8_t y2, uint8_t y3,
uint8_t z0, uint8_t z1, uint8_t z2, uint8_t z3,
uint8_t w0, uint8_t w1, uint8_t w2, uint8_t w3) {
vec128_t v;
v.u8[0] = x3;
v.u8[1] = x2;
v.u8[2] = x1;
v.u8[3] = x0;
v.u8[4] = y3;
v.u8[5] = y2;
v.u8[6] = y1;
v.u8[7] = y0;
v.u8[8] = z3;
v.u8[9] = z2;
v.u8[10] = z1;
v.u8[11] = z0;
v.u8[12] = w3;
v.u8[13] = w2;
v.u8[14] = w1;
v.u8[15] = w0;
return v;
}
} // namespace poly
#endif // POLY_VEC128_H_