mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-30 12:47:48 +02:00
221 lines
6.1 KiB
C++
221 lines
6.1 KiB
C++
/*
|
|
* Copyright (c) 2013-2022, The PurpleI2P Project
|
|
*
|
|
* This file is part of Purple i2pd project and licensed under BSD3
|
|
*
|
|
* See full license text in LICENSE file at top of project tree
|
|
*/
|
|
|
|
#ifndef UTIL_H
|
|
#define UTIL_H
|
|
|
|
#include <string>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include <utility>
|
|
#include <boost/asio.hpp>
|
|
|
|
#ifdef ANDROID
|
|
#ifndef __clang__
|
|
#include <boost/lexical_cast.hpp>
|
|
namespace std
|
|
{
|
|
template <typename T>
|
|
std::string to_string(T value)
|
|
{
|
|
return boost::lexical_cast<std::string>(value);
|
|
}
|
|
|
|
inline int stoi(const std::string& str)
|
|
{
|
|
return boost::lexical_cast<int>(str);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
namespace i2p {
|
|
namespace util {
|
|
|
|
template<class T>
|
|
class MemoryPool {
|
|
//BOOST_STATIC_ASSERT_MSG(sizeof(T) >= sizeof(void*), "size cannot be less that general pointer size");
|
|
|
|
public:
|
|
|
|
MemoryPool() : m_Head(nullptr) {}
|
|
|
|
~MemoryPool() {
|
|
CleanUp();
|
|
}
|
|
|
|
void CleanUp() {
|
|
CleanUp(m_Head);
|
|
m_Head = nullptr;
|
|
}
|
|
|
|
template<typename... TArgs>
|
|
T *Acquire(TArgs &&... args) {
|
|
if (!m_Head) return new T(std::forward<TArgs>(args)...);
|
|
else {
|
|
auto tmp = m_Head;
|
|
m_Head = static_cast<T *>(*(void **) m_Head); // next
|
|
return new(tmp)T(std::forward<TArgs>(args)...);
|
|
}
|
|
}
|
|
|
|
void Release(T *t) {
|
|
if (!t) return;
|
|
t->~T();
|
|
*(void **) t = m_Head; // next
|
|
m_Head = t;
|
|
}
|
|
|
|
template<typename... TArgs>
|
|
std::unique_ptr <T, std::function<void(T *)>> AcquireUnique(TArgs &&... args) {
|
|
return std::unique_ptr < T, std::function < void(T * ) > > (Acquire(std::forward<TArgs>(args)...),
|
|
std::bind(&MemoryPool<T>::Release, this, std::placeholders::_1));
|
|
}
|
|
|
|
template<typename... TArgs>
|
|
std::shared_ptr <T> AcquireShared(TArgs &&... args) {
|
|
return std::shared_ptr<T>(Acquire(std::forward<TArgs>(args)...),
|
|
std::bind(&MemoryPool<T>::Release, this, std::placeholders::_1));
|
|
}
|
|
|
|
protected:
|
|
|
|
void CleanUp(T *head) {
|
|
while (head) {
|
|
auto tmp = head;
|
|
head = static_cast<T *>(*(void **) head); // next
|
|
::operator delete((void *) tmp);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
|
|
T *m_Head;
|
|
};
|
|
|
|
template<class T>
|
|
class MemoryPoolMt : public MemoryPool<T> {
|
|
public:
|
|
|
|
MemoryPoolMt() {}
|
|
|
|
template<typename... TArgs>
|
|
T *AcquireMt(TArgs &&... args) {
|
|
if (!this->m_Head) return new T(std::forward<TArgs>(args)...);
|
|
std::lock_guard <std::mutex> l(m_Mutex);
|
|
return this->Acquire(std::forward<TArgs>(args)...);
|
|
}
|
|
|
|
void ReleaseMt(T *t) {
|
|
std::lock_guard <std::mutex> l(m_Mutex);
|
|
this->Release(t);
|
|
}
|
|
|
|
template<template<typename, typename...> class C, typename... R>
|
|
void ReleaseMt(const C<T *, R...> &c) {
|
|
std::lock_guard <std::mutex> l(m_Mutex);
|
|
for (auto &it: c)
|
|
this->Release(it);
|
|
}
|
|
|
|
template<typename... TArgs>
|
|
std::shared_ptr <T> AcquireSharedMt(TArgs &&... args) {
|
|
return std::shared_ptr<T>(AcquireMt(std::forward<TArgs>(args)...),
|
|
std::bind < void(MemoryPoolMt<T>::*)(T * ) >
|
|
(&MemoryPoolMt<T>::ReleaseMt, this, std::placeholders::_1));
|
|
}
|
|
|
|
void CleanUpMt() {
|
|
T *head;
|
|
{
|
|
std::lock_guard <std::mutex> l(m_Mutex);
|
|
head = this->m_Head;
|
|
this->m_Head = nullptr;
|
|
}
|
|
if (head) this->CleanUp(head);
|
|
}
|
|
|
|
private:
|
|
|
|
std::mutex m_Mutex;
|
|
};
|
|
|
|
class RunnableService {
|
|
protected:
|
|
|
|
RunnableService(const std::string &name) : m_Name(name), m_IsRunning(false) {}
|
|
|
|
virtual ~RunnableService() {}
|
|
|
|
boost::asio::io_service &GetIOService() { return m_Service; }
|
|
|
|
bool IsRunning() const { return m_IsRunning; };
|
|
|
|
void StartIOService();
|
|
|
|
void StopIOService();
|
|
|
|
private:
|
|
|
|
void Run();
|
|
|
|
private:
|
|
|
|
std::string m_Name;
|
|
volatile bool m_IsRunning;
|
|
std::unique_ptr <std::thread> m_Thread;
|
|
boost::asio::io_service m_Service;
|
|
};
|
|
|
|
class RunnableServiceWithWork : public RunnableService {
|
|
protected:
|
|
|
|
RunnableServiceWithWork(const std::string &name) :
|
|
RunnableService(name), m_Work(GetIOService()) {}
|
|
|
|
private:
|
|
|
|
boost::asio::io_service::work m_Work;
|
|
};
|
|
|
|
void SetThreadName(const char *name);
|
|
|
|
template<typename T>
|
|
class SaveStateHelper {
|
|
public:
|
|
|
|
SaveStateHelper(T &orig) : m_Original(orig), m_Copy(orig) {};
|
|
|
|
~SaveStateHelper() { m_Original = m_Copy; };
|
|
|
|
private:
|
|
|
|
T &m_Original;
|
|
T m_Copy;
|
|
};
|
|
|
|
namespace net {
|
|
int GetMTU(const boost::asio::ip::address &localAddress);
|
|
|
|
int GetMaxMTU(const boost::asio::ip::address_v6 &localAddress); // check tunnel broker for ipv6 address
|
|
const boost::asio::ip::address GetInterfaceAddress(const std::string &ifname, bool ipv6 = false);
|
|
|
|
boost::asio::ip::address_v6 GetYggdrasilAddress();
|
|
|
|
bool IsLocalAddress(const boost::asio::ip::address &addr);
|
|
|
|
bool IsInReservedRange(const boost::asio::ip::address &host);
|
|
|
|
bool IsYggdrasilAddress(const boost::asio::ip::address &addr);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|