在写一些大型项目的过程中经常需要一些工具函数,例如获取随机数、计时器、打印函数、重要常量(如最大值)、信号与槽等,由于每一个工程都自己手动实现一个实在是太傻,我将其总结放入一个文件中。
utils.h
// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2022/6/27
// Description:
#ifndef UTILS_H
#define UTILS_H#include "json.hpp"
#include <iostream>
#include <random>
#include <chrono>
#include <fstream>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <functional>namespace edward {constexpr int INF = 0x3f3f3f3f;//extern std::ofstream ofs;inline void print() {std::cout << "\n";
// ofs << "\n";
}
template<typename T, typename... Args>
void print(T&& first, Args&&... args) {std::cout << first << " ";
// ofs << first << " ";print(std::forward<Args>(args)...);
}template<typename Iter>
void printArr(Iter begin, Iter end) {while (begin != end) {std::cout << *begin++ << " ";}std::cout << "\n";
}template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& pr) {os << pr.first << " " << pr.second;return os;
}template<typename Container>
void printArr(const Container& container) {for (auto x : container) {std::cout << x << " ";}std::cout << "\n";
}class Random {
public:// random number generator.static std::mt19937 pseudoRandNumGen;static void initRand(int seed) { pseudoRandNumGen = std::mt19937(seed); } //设置随机数种子static int fastRand(int lb, int ub) { return (pseudoRandNumGen() % (ub - lb)) + lb; }static int fastRand(int ub) { return pseudoRandNumGen() % ub; }static int rand(int lb, int ub) { return std::uniform_int_distribution<int>(lb, ub - 1)(pseudoRandNumGen); }static int rand(int ub) { return std::uniform_int_distribution<int>(0, ub - 1)(pseudoRandNumGen); }
};class Timer {std::chrono::time_point<std::chrono::system_clock> timePoint_;
public:Timer(): timePoint_(std::chrono::system_clock::now()) {}Timer(const Timer&) = delete;~Timer() = default;void operator() (const std::string& msg) {auto duration = std::chrono::system_clock::now() - timePoint_;print(msg, static_cast<double>(duration.count()) / decltype(duration)::period::den, "s");}void reset() {timePoint_ = std::chrono::system_clock::now();}void operator() (nlohmann::json& arr) {auto duration = std::chrono::system_clock::now() - timePoint_;arr.push_back(duration.count());}};using Slot = std::shared_ptr<void>;//前置声明
template<typename Signature>
class Signal;
template<typename Ret, typename... Args>
class Signal<Ret(Args...)>;namespace detail {//前置声明template<typename Callback> class SlotImpl;template<typename Callback>class SignalImpl {public:using SlotList = std::unordered_map<SlotImpl<Callback> *, std::weak_ptr<SlotImpl<Callback>>>;SignalImpl(): slots_(new SlotList), mutex_() {}~SignalImpl() {}//只能在加锁后使用void cowWithLock() {if (!slots_.unique()) {slots_.reset(new SlotList(*slots_));}}//添加槽函数void add(const std::shared_ptr<SlotImpl<Callback>> &slot) {std::lock_guard<std::mutex> lockGuard(mutex_);cowWithLock();slots_->insert({slot.get(), slot});}//供SlotImpl调用,删除槽函数void remove(SlotImpl<Callback> *slot) {std::lock_guard<std::mutex> lockGuard(mutex_);cowWithLock();slots_->erase(slot);}std::shared_ptr<SlotList> getSlotList() {std::lock_guard<std::mutex> lockGuard(mutex_);return slots_;}private:std::mutex mutex_;//保存SlotImpl的weak_ptr//之所以不保存SlotList而是保存其shared_ptr是为了实现COWstd::shared_ptr<SlotList> slots_;};template<typename Callback>class SlotImpl {public:SlotImpl(Callback&& cb, const std::shared_ptr<SignalImpl<Callback>> &signal): cb_(cb), signal_(signal) {}~SlotImpl() {auto signal = signal_.lock();if (signal) {signal->remove(this);}}Callback cb_;private://保存SignalImpl的weak_ptrstd::weak_ptr<SignalImpl<Callback>> signal_;};
}template<typename Ret, typename... Args>
class Signal<Ret(Args...)> {
public:using Callback = std::function<Ret(Args...)>;using SignalImpl = detail::SignalImpl<Callback>;using SlotImpl = detail::SlotImpl<Callback>;Signal(): impl_(new SignalImpl) {}~Signal() {}/*!* 添加槽函数* @param cb 槽函数* @return 需要保存这个智能指针,否则会自动从槽函数列表中删除*/template<typename Func>Slot connect(Func&& cb) {std::shared_ptr<SlotImpl> slot(new SlotImpl(std::forward<Func>(cb), impl_));impl_->add(slot);return slot;}template<typename ...ARGS>void operator() (ARGS&&... args) {auto slots = impl_->getSlotList();//使用引用避免智能指针的解引用auto &s = *slots;for (auto &&[pSlotImpl, pWkSlotImpl] : s) {auto pShrSlotImpl = pWkSlotImpl.lock();if (pShrSlotImpl) {pShrSlotImpl->cb_(std::forward<ARGS>(args)...);}}}private://保存shared_ptr的原因是需要传递给SlotImpl,在SlotImpl析构的时候会清除自己const std::shared_ptr<SignalImpl> impl_;
};}#endif //UTILS_H
utils.cpp
// Copyright(C), Edward-Elric233
// Author: Edward-Elric233
// Version: 1.0
// Date: 2022/6/27
// Description:
#include "utils.h"namespace edward {std::mt19937 Random::pseudoRandNumGen(std::chrono::system_clock::now().time_since_epoch().count()); //默认使用当下时间戳初始化随机数种子,精确到纳秒//std::ofstream ofs("../test/debug.txt");}