You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
4.9 KiB
C++
194 lines
4.9 KiB
C++
#pragma once
|
|
// Copyright 2020 TooYoungTooSimp <lyc@xuming.studio>, All rights reserved.
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#ifndef _UTILITIES_H_
|
|
#define _UTILITIES_H_
|
|
#include <algorithm>
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <random>
|
|
#include <string>
|
|
|
|
static void __strconcat_impl(std::string &res) {}
|
|
template <typename T, typename... TArgs>
|
|
static void __strconcat_impl(std::string &res, const T &arg, const TArgs &... args)
|
|
{
|
|
res.append(arg);
|
|
__strconcat_impl(res, args...);
|
|
}
|
|
template <typename... TArgs>
|
|
static std::string strconcat(TArgs... args)
|
|
{
|
|
std::string res;
|
|
__strconcat_impl(res, args...);
|
|
return res;
|
|
}
|
|
|
|
class spin_lock
|
|
{
|
|
private:
|
|
std::atomic<bool> flag = false;
|
|
|
|
public:
|
|
spin_lock() = default;
|
|
spin_lock(const spin_lock &) = delete;
|
|
spin_lock &operator=(const spin_lock &) = delete;
|
|
void lock()
|
|
{
|
|
bool target = false;
|
|
while (!flag.compare_exchange_strong(target, true))
|
|
target = false;
|
|
}
|
|
void unlock() { flag.store(false); }
|
|
};
|
|
|
|
#ifdef _WIN32
|
|
// clang-format off
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
#include <wincrypt.h>
|
|
#include <Psapi.h>
|
|
#pragma comment(lib, "Advapi32.lib")
|
|
#pragma comment(lib, "user32.lib")
|
|
// clang-format on
|
|
static size_t __get_working_set_size()
|
|
{
|
|
PROCESS_MEMORY_COUNTERS ProcessMemoryCounters;
|
|
GetProcessMemoryInfo(GetCurrentProcess(), &ProcessMemoryCounters, sizeof(PROCESS_MEMORY_COUNTERS));
|
|
return ProcessMemoryCounters.WorkingSetSize;
|
|
}
|
|
class MemoryMonitor
|
|
{
|
|
private:
|
|
static spin_lock lock;
|
|
static int64_t global_counter;
|
|
static std::map<MemoryMonitor *, int64_t *> M;
|
|
int64_t max_counter;
|
|
int64_t counter;
|
|
int64_t result;
|
|
_CRT_ALLOC_HOOK _orig_alloc_hook;
|
|
static size_t __get_block_size(void *ptr) { return *((size_t *)ptr - 4 + (sizeof(size_t) >> 2)); }
|
|
static int __crt_alloc_hook(int allocType, void *ptr, size_t size,
|
|
int blockType, long requestNumber,
|
|
const unsigned char *filename, int lineNumber);
|
|
|
|
public:
|
|
MemoryMonitor()
|
|
{
|
|
std::lock_guard<spin_lock> guard(lock);
|
|
if (M.empty())
|
|
{
|
|
_orig_alloc_hook = _CrtGetAllocHook();
|
|
_CrtSetAllocHook(__crt_alloc_hook);
|
|
}
|
|
M[this] = &max_counter;
|
|
reset();
|
|
}
|
|
~MemoryMonitor()
|
|
{
|
|
std::lock_guard<spin_lock> guard(lock);
|
|
M.erase(this);
|
|
if (M.empty())
|
|
_CrtSetAllocHook(_orig_alloc_hook);
|
|
}
|
|
void reset() { max_counter = counter = global_counter; }
|
|
void save() { result = max_counter - counter; }
|
|
int64_t max_usage() const { return result; }
|
|
};
|
|
|
|
static unsigned int __get_random_seed()
|
|
{
|
|
unsigned int r = 0;
|
|
HCRYPTPROV hCryptProv;
|
|
CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);
|
|
CryptGenRandom(hCryptProv, sizeof(unsigned int), (BYTE *)&r);
|
|
CryptReleaseContext(hCryptProv, 0);
|
|
return r;
|
|
}
|
|
static void __error_then_exit(const char *msg)
|
|
{
|
|
MessageBoxA(NULL, msg, "Error", MB_OK | MB_ICONERROR);
|
|
exit(1);
|
|
}
|
|
#else
|
|
unsigned int __get_random_seed()
|
|
{
|
|
unsigned int r = 0;
|
|
FILE *fd = fopen("/dev/random", "rb");
|
|
fread(&r, sizeof(unsigned int), 1, fd);
|
|
fclose(fd);
|
|
return r;
|
|
}
|
|
void __error_then_exit(const char *msg)
|
|
{
|
|
fputs(msg, stderr);
|
|
getchar(), getchar();
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
class Random
|
|
{
|
|
private:
|
|
std::mt19937 *rd;
|
|
|
|
public:
|
|
Random() { rd = new std::mt19937(__get_random_seed()); }
|
|
~Random() { delete rd; }
|
|
unsigned int next() { return (*rd)(); }
|
|
unsigned int next(unsigned int mn, unsigned int mx) { return next() % (mx - mn) + mn; }
|
|
};
|
|
|
|
class FileHandleExitOnFail
|
|
{
|
|
private:
|
|
FILE *fp;
|
|
|
|
public:
|
|
FileHandleExitOnFail(FILE *_fp) : fp(_fp) {}
|
|
FileHandleExitOnFail(const char *filename, const char *mode)
|
|
{
|
|
fp = fopen(filename, mode);
|
|
if (!fp)
|
|
{
|
|
auto msg = strconcat("Failed to open ", filename);
|
|
__error_then_exit(msg.c_str());
|
|
}
|
|
}
|
|
~FileHandleExitOnFail() { fclose(fp); }
|
|
operator FILE *() const { return fp; }
|
|
};
|
|
|
|
class Timer
|
|
{
|
|
public:
|
|
using fmilliseconds = std::chrono::duration<double, std::milli>;
|
|
void start() { t1 = std::chrono::steady_clock::now(); }
|
|
void stop() { t2 = std::chrono::steady_clock::now(); }
|
|
std::chrono::steady_clock::duration::rep difference() { return (t2 - t1).count(); }
|
|
double diff_in_ms() { return std::chrono::duration_cast<fmilliseconds>(t2 - t1).count(); }
|
|
|
|
private:
|
|
std::chrono::time_point<std::chrono::steady_clock> t1, t2;
|
|
};
|
|
|
|
template <typename T>
|
|
class Array2DView
|
|
{
|
|
private:
|
|
T *arr;
|
|
size_t w;
|
|
|
|
public:
|
|
Array2DView(size_t _w, T *ptr = nullptr) : arr(ptr), w(_w) {}
|
|
Array2DView<T> &operator=(T *ptr) { arr = ptr; }
|
|
void resize(size_t _w) { w = _w; }
|
|
T *operator[](size_t idx) { return arr + idx * w; }
|
|
T *data() const { return arr; }
|
|
};
|
|
|
|
#endif |