Initial engine repository
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveListValue;
|
||||
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveList {
|
||||
public:
|
||||
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
IntrusiveList()
|
||||
: first_(nullptr)
|
||||
, last_(nullptr) {
|
||||
}
|
||||
|
||||
~IntrusiveList() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
const value_type& GetFirst() const {
|
||||
return first_;
|
||||
}
|
||||
|
||||
value_type& GetFirst() {
|
||||
return first_;
|
||||
}
|
||||
|
||||
const value_type& GetLast() const {
|
||||
return last_;
|
||||
}
|
||||
|
||||
value_type& GetLast() {
|
||||
return last_;
|
||||
}
|
||||
|
||||
inline bool IsEmpty() const {
|
||||
return first_ == nullptr;
|
||||
}
|
||||
|
||||
void PushBack(reference child) {
|
||||
if (child->GetPrev()) {
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
}
|
||||
if (child->GetNext()) {
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
}
|
||||
|
||||
child->GetPrev() = last_;
|
||||
child->GetNext() = nullptr;
|
||||
|
||||
if (first_) {
|
||||
last_->GetNext() = child;
|
||||
} else {
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
void PushFront(reference child) {
|
||||
if (child->GetPrev()) {
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
}
|
||||
if (child->GetNext()) {
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
}
|
||||
|
||||
child->GetPrev() = nullptr;
|
||||
child->GetNext() = first_;
|
||||
|
||||
if (first_) {
|
||||
first_->GetPrev() = child;
|
||||
} else {
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
void InsertBefore(reference child, reference before) {
|
||||
if (child->GetPrev()) {
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
}
|
||||
if (child->GetNext()) {
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
}
|
||||
|
||||
if (before->GetPrev()) {
|
||||
before->GetPrev()->GetNext() = child;
|
||||
} else {
|
||||
first_ = child;
|
||||
}
|
||||
|
||||
child->GetPrev() = before->GetPrev();
|
||||
child->GetNext() = before;
|
||||
before->GetPrev() = child;
|
||||
}
|
||||
|
||||
void InsertAfter(reference child, reference after) {
|
||||
if (child->GetPrev()) {
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
}
|
||||
if (child->GetNext()) {
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
}
|
||||
|
||||
if (after->GetNext()) {
|
||||
after->GetNext()->GetPrev() = child;
|
||||
} else {
|
||||
last_ = child;
|
||||
}
|
||||
|
||||
child->GetNext() = after->GetNext();
|
||||
child->GetPrev() = after;
|
||||
after->GetNext() = child;
|
||||
}
|
||||
|
||||
void Remove(reference child) {
|
||||
if (child->GetNext()) {
|
||||
child->GetNext()->GetPrev() = child->GetPrev();
|
||||
} else {
|
||||
last_ = child->GetPrev();
|
||||
}
|
||||
|
||||
if (child->GetPrev()) {
|
||||
child->GetPrev()->GetNext() = child->GetNext();
|
||||
} else {
|
||||
first_ = child->GetNext();
|
||||
}
|
||||
|
||||
child->GetPrev() = nullptr;
|
||||
child->GetNext() = nullptr;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
value_type p = first_;
|
||||
while (p) {
|
||||
value_type tmp = p;
|
||||
p = p->GetNext();
|
||||
if (tmp) {
|
||||
tmp->GetNext() = nullptr;
|
||||
tmp->GetPrev() = nullptr;
|
||||
}
|
||||
}
|
||||
first_ = nullptr;
|
||||
last_ = nullptr;
|
||||
}
|
||||
|
||||
bool CheckValid() {
|
||||
if (!first_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
|
||||
value_type p = first_;
|
||||
value_type tmp = p;
|
||||
do {
|
||||
tmp = p;
|
||||
p = p->GetNext();
|
||||
++pos;
|
||||
|
||||
if (p) {
|
||||
if (p->GetPrev() != tmp) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tmp != last_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (p);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename _IterPtrTy>
|
||||
struct Iterator {
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = _IterPtrTy;
|
||||
using pointer = _IterPtrTy*;
|
||||
using reference = _IterPtrTy&;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
inline Iterator(value_type ptr = nullptr, bool is_end = false)
|
||||
: base_(ptr)
|
||||
, is_end_(is_end) {
|
||||
}
|
||||
|
||||
inline reference operator*() const {
|
||||
assert(base_ && !is_end_);
|
||||
return const_cast<reference>(base_);
|
||||
}
|
||||
|
||||
inline pointer operator->() const {
|
||||
return std::pointer_traits<pointer>::pointer_to(**this);
|
||||
}
|
||||
|
||||
inline Iterator& operator++() {
|
||||
assert(base_ && !is_end_);
|
||||
value_type next = base_->GetNext();
|
||||
if (next) {
|
||||
base_ = next;
|
||||
} else {
|
||||
is_end_ = true;
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Iterator operator++(int) {
|
||||
Iterator old = (*this);
|
||||
++(*this);
|
||||
return old;
|
||||
}
|
||||
|
||||
inline Iterator& operator--() {
|
||||
assert(base_);
|
||||
if (is_end_) {
|
||||
is_end_ = false;
|
||||
} else {
|
||||
base_ = base_->GetPrev();
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
|
||||
inline Iterator operator--(int) {
|
||||
Iterator old = (*this);
|
||||
--(*this);
|
||||
return old;
|
||||
}
|
||||
|
||||
inline bool operator==(const Iterator& other) const {
|
||||
return base_ == other.base_ && is_end_ == other.is_end_;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline operator bool() const {
|
||||
return base_ != nullptr && !is_end_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_end_;
|
||||
|
||||
typename std::remove_const<value_type>::type base_;
|
||||
};
|
||||
|
||||
public:
|
||||
using iterator = Iterator<value_type>;
|
||||
using const_iterator = Iterator<const value_type>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
inline iterator begin() {
|
||||
return iterator(first_, first_ == nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator begin() const {
|
||||
return const_iterator(first_, first_ == nullptr);
|
||||
}
|
||||
|
||||
inline const_iterator cbegin() const {
|
||||
return begin();
|
||||
}
|
||||
|
||||
inline iterator end() {
|
||||
return iterator(last_, true);
|
||||
}
|
||||
|
||||
inline const_iterator end() const {
|
||||
return const_iterator(last_, true);
|
||||
}
|
||||
|
||||
inline const_iterator cend() const {
|
||||
return end();
|
||||
}
|
||||
|
||||
inline reverse_iterator rbegin() {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator rbegin() const {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator crbegin() const {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
inline reverse_iterator rend() {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator rend() const {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
inline const_reverse_iterator crend() const {
|
||||
return rend();
|
||||
}
|
||||
|
||||
inline value_type& front() {
|
||||
if (IsEmpty()) {
|
||||
throw std::out_of_range("front() called on empty list");
|
||||
}
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline const value_type& front() const {
|
||||
if (IsEmpty()) {
|
||||
throw std::out_of_range("front() called on empty list");
|
||||
}
|
||||
return first_;
|
||||
}
|
||||
|
||||
inline value_type& back() {
|
||||
if (IsEmpty()) {
|
||||
throw std::out_of_range("back() called on empty list");
|
||||
}
|
||||
return last_;
|
||||
}
|
||||
|
||||
inline const value_type& back() const {
|
||||
if (IsEmpty()) {
|
||||
throw std::out_of_range("back() called on empty list");
|
||||
}
|
||||
return last_;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type first_;
|
||||
value_type last_;
|
||||
|
||||
template <typename T>
|
||||
friend class IntrusiveListValue;
|
||||
};
|
||||
|
||||
template <typename _PtrTy>
|
||||
class IntrusiveListValue {
|
||||
public:
|
||||
using value_type = typename std::pointer_traits<_PtrTy>::pointer;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
|
||||
IntrusiveListValue()
|
||||
: prev_(nullptr)
|
||||
, next_(nullptr) {
|
||||
}
|
||||
|
||||
IntrusiveListValue(value_type rhs)
|
||||
: prev_(nullptr)
|
||||
, next_(nullptr) {
|
||||
if (rhs) {
|
||||
prev_ = rhs->GetPrev();
|
||||
next_ = rhs->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
const value_type& GetPrev() const {
|
||||
return prev_;
|
||||
}
|
||||
|
||||
value_type& GetPrev() {
|
||||
return prev_;
|
||||
}
|
||||
|
||||
const value_type& GetNext() const {
|
||||
return next_;
|
||||
}
|
||||
|
||||
value_type& GetNext() {
|
||||
return next_;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type prev_;
|
||||
value_type next_;
|
||||
|
||||
template <typename T>
|
||||
friend class IntrusiveList;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace frostbite2D {
|
||||
|
||||
class StartupTrace {
|
||||
public:
|
||||
static constexpr bool enabled() {
|
||||
#ifndef NDEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void reset(const char* label = nullptr) {
|
||||
if (!enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Uint64 now = SDL_GetPerformanceCounter();
|
||||
std::string line;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex());
|
||||
startCounter() = now;
|
||||
if (label && label[0] != '\0') {
|
||||
line = std::string("[Startup] reset: ") + label;
|
||||
clearLogFileUnlocked();
|
||||
writeLineUnlocked(line);
|
||||
} else {
|
||||
clearLogFileUnlocked();
|
||||
}
|
||||
}
|
||||
if (!line.empty()) {
|
||||
SDL_Log("%s", line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static double totalElapsedMs() {
|
||||
if (!enabled()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Uint64 start = 0;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex());
|
||||
start = startCounter();
|
||||
}
|
||||
|
||||
if (start == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Uint64 now = SDL_GetPerformanceCounter();
|
||||
Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
if (frequency == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return static_cast<double>(now - start) * 1000.0 /
|
||||
static_cast<double>(frequency);
|
||||
}
|
||||
|
||||
static void mark(const char* label) {
|
||||
if (!enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[256] = {};
|
||||
SDL_snprintf(buffer, sizeof(buffer),
|
||||
"[Startup] %s reached at %.2f ms (thread=%u)",
|
||||
label ? label : "<unnamed>", totalElapsedMs(), SDL_ThreadID());
|
||||
logLine(buffer);
|
||||
SDL_Log("%s", buffer);
|
||||
}
|
||||
|
||||
static void logLine(const std::string& line) {
|
||||
if (!enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex());
|
||||
writeLineUnlocked(line);
|
||||
}
|
||||
|
||||
private:
|
||||
static Uint64& startCounter() {
|
||||
static Uint64 counter = 0;
|
||||
return counter;
|
||||
}
|
||||
|
||||
static std::mutex& mutex() {
|
||||
static std::mutex value;
|
||||
return value;
|
||||
}
|
||||
|
||||
static const char* logFilePath() {
|
||||
return "startup_trace.log";
|
||||
}
|
||||
|
||||
static void clearLogFileUnlocked() {
|
||||
std::ofstream stream(logFilePath(), std::ios::trunc);
|
||||
}
|
||||
|
||||
static void writeLineUnlocked(const std::string& line) {
|
||||
std::ofstream stream(logFilePath(), std::ios::app);
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
stream << line << '\n';
|
||||
}
|
||||
};
|
||||
|
||||
class ScopedStartupTrace {
|
||||
public:
|
||||
explicit ScopedStartupTrace(const char* label)
|
||||
: label_(label ? label : "<unnamed>"),
|
||||
startCounter_(SDL_GetPerformanceCounter()) {}
|
||||
|
||||
~ScopedStartupTrace() {
|
||||
if (!StartupTrace::enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Uint64 now = SDL_GetPerformanceCounter();
|
||||
Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
double elapsedMs = 0.0;
|
||||
if (frequency != 0) {
|
||||
elapsedMs = static_cast<double>(now - startCounter_) * 1000.0 /
|
||||
static_cast<double>(frequency);
|
||||
}
|
||||
|
||||
char buffer[256] = {};
|
||||
SDL_snprintf(buffer, sizeof(buffer),
|
||||
"[Startup] %s took %.2f ms (total %.2f ms, thread=%u)",
|
||||
label_, elapsedMs, StartupTrace::totalElapsedMs(),
|
||||
SDL_ThreadID());
|
||||
StartupTrace::logLine(buffer);
|
||||
SDL_Log("%s", buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
const char* label_;
|
||||
Uint64 startCounter_ = 0;
|
||||
};
|
||||
|
||||
} // namespace frostbite2D
|
||||
Reference in New Issue
Block a user