Allow copy-assigning one Env object to the other.
This commit is contained in:
parent
dfefed1516
commit
01e40d297e
9 changed files with 189 additions and 20 deletions
|
@ -17,8 +17,56 @@
|
||||||
|
|
||||||
#include "env_base.hpp"
|
#include "env_base.hpp"
|
||||||
#include "string_view_cat.hpp"
|
#include "string_view_cat.hpp"
|
||||||
|
#include "safe_print.hpp"
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace duck {
|
namespace duck {
|
||||||
|
namespace {
|
||||||
|
template <typename F, typename R=decltype(std::declval<F>()())>
|
||||||
|
R call_noexcept (F func, std::string_view err_location) noexcept {
|
||||||
|
typedef R return_type;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error& err) {
|
||||||
|
safe_print_error("Unexpected exception in ");
|
||||||
|
safe_print_error(err_location);
|
||||||
|
safe_print_error(": ");
|
||||||
|
safe_print_error_ln(err.what());
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
safe_print_error("Unknown exception in ");
|
||||||
|
safe_print_error_ln(err_location);
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (not std::is_same<void, return_type>::value)
|
||||||
|
return return_type{};
|
||||||
|
}
|
||||||
|
} //unnamed namespace
|
||||||
|
|
||||||
|
class StdMutex : public EnvBase::Mutex {
|
||||||
|
public:
|
||||||
|
StdMutex (std::mutex& m) noexcept :
|
||||||
|
m_mutex(m)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual void lock() override { m_mutex.lock(); }
|
||||||
|
virtual void try_lock() override {m_mutex.try_lock(); }
|
||||||
|
virtual void unlock() noexcept override {m_mutex.unlock(); }
|
||||||
|
private:
|
||||||
|
std::mutex& m_mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EmptyMutex : public EnvBase::Mutex {
|
||||||
|
public:
|
||||||
|
EmptyMutex() noexcept = default;
|
||||||
|
virtual void lock() override { }
|
||||||
|
virtual void try_lock() override { }
|
||||||
|
virtual void unlock() noexcept override { }
|
||||||
|
};
|
||||||
|
|
||||||
bool EnvBase::empty() const noexcept {
|
bool EnvBase::empty() const noexcept {
|
||||||
return 0 == this->size();
|
return 0 == this->size();
|
||||||
}
|
}
|
||||||
|
@ -38,4 +86,26 @@ detail::EnvVarProxy<std::string> EnvBase::operator[] (std::string&& name) noexce
|
||||||
detail::EnvVarProxy<std::string> EnvBase::operator[] (const std::string& name) noexcept {
|
detail::EnvVarProxy<std::string> EnvBase::operator[] (const std::string& name) noexcept {
|
||||||
return {to_string(name), this};
|
return {to_string(name), this};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EnvBase::set (std::string_view name, std::string_view value) {
|
||||||
|
StdMutex m(this->mutex());
|
||||||
|
this->set_implem(name, value, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvBase::set_nolock (EnvBase& obj, std::string_view name, std::string_view value) {
|
||||||
|
EmptyMutex m;
|
||||||
|
obj.set_implem(name, value, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvBase::clear() noexcept {
|
||||||
|
StdMutex m(this->mutex());
|
||||||
|
call_noexcept([this,&m](){this->clear_implem(m);}, to_string_view(__func__));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvBase::clear_nolock (EnvBase& obj) noexcept {
|
||||||
|
EmptyMutex m;
|
||||||
|
call_noexcept([&](){obj.clear_implem(m);}, to_string_view(__func__));
|
||||||
|
return;
|
||||||
|
}
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace duck {
|
namespace duck {
|
||||||
class EnvBase;
|
class EnvBase;
|
||||||
|
@ -47,6 +48,13 @@ namespace duck {
|
||||||
typedef std::size_t size_type;
|
typedef std::size_t size_type;
|
||||||
typedef std::ptrdiff_t difference_type;
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
|
||||||
|
struct Mutex {
|
||||||
|
virtual ~Mutex() noexcept = default;
|
||||||
|
virtual void lock() = 0;
|
||||||
|
virtual void try_lock() = 0;
|
||||||
|
virtual void unlock() noexcept = 0;
|
||||||
|
};
|
||||||
|
|
||||||
EnvBase() = default;
|
EnvBase() = default;
|
||||||
EnvBase (const EnvBase&) = delete;
|
EnvBase (const EnvBase&) = delete;
|
||||||
EnvBase (EnvBase&&) = delete;
|
EnvBase (EnvBase&&) = delete;
|
||||||
|
@ -59,12 +67,22 @@ namespace duck {
|
||||||
|
|
||||||
virtual std::optional<std::string_view> get (std::string_view name) const noexcept = 0;
|
virtual std::optional<std::string_view> get (std::string_view name) const noexcept = 0;
|
||||||
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept = 0;
|
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept = 0;
|
||||||
virtual void set (std::string_view name, std::string_view value) = 0;
|
void set (std::string_view name, std::string_view value);
|
||||||
virtual void unset (std::string_view name) noexcept = 0;
|
virtual void unset (std::string_view name) noexcept = 0;
|
||||||
virtual bool is_set (std::string_view name) const noexcept = 0;
|
virtual bool is_set (std::string_view name) const noexcept = 0;
|
||||||
virtual size_type size() const noexcept = 0;
|
virtual size_type size() const noexcept = 0;
|
||||||
virtual bool empty() const noexcept;
|
virtual bool empty() const noexcept;
|
||||||
virtual void clear() noexcept = 0;
|
void clear() noexcept;
|
||||||
|
|
||||||
|
virtual std::mutex& mutex() noexcept = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void set_all_into (EnvBase& other) const = 0;
|
||||||
|
static void set_all_into (const EnvBase& obj, EnvBase& other) { obj.set_all_into(other); }
|
||||||
|
virtual void clear_implem(Mutex& m) = 0;
|
||||||
|
static void clear_nolock (EnvBase& obj) noexcept;
|
||||||
|
virtual void set_implem (std::string_view name, std::string_view value, Mutex& m) = 0;
|
||||||
|
static void set_nolock (EnvBase& obj, std::string_view name, std::string_view value);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
|
@ -87,7 +87,7 @@ std::string_view EnvFake::get (std::string_view name, std::string_view def) cons
|
||||||
return maybe_ret;
|
return maybe_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvFake::set (std::string_view name, std::string_view value) {
|
void EnvFake::set_implem (std::string_view name, std::string_view value, Mutex& m) {
|
||||||
assert(not name.empty());
|
assert(not name.empty());
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -102,10 +102,13 @@ void EnvFake::set (std::string_view name, std::string_view value) {
|
||||||
const std::string_view new_value(buff.get() + name.size(), value.size());
|
const std::string_view new_value(buff.get() + name.size(), value.size());
|
||||||
assert(new_value == value);
|
assert(new_value == value);
|
||||||
|
|
||||||
m_map_strong_cpy.insert_or_assign(std::string_view(new_name), std::move(buff));
|
{
|
||||||
m_map.insert_or_assign(std::string_view(new_name), std::string_view(new_value));
|
std::lock_guard<Mutex> lock(m);
|
||||||
assert(m_map.at(name) == value);
|
m_map_strong_cpy.insert_or_assign(std::string_view(new_name), std::move(buff));
|
||||||
assert(m_map.find(name)->first.data() == new_name.data());
|
m_map.insert_or_assign(std::string_view(new_name), std::string_view(new_value));
|
||||||
|
assert(m_map.at(name) == value);
|
||||||
|
assert(m_map.find(name)->first.data() == new_name.data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvFake::unset (std::string_view name) noexcept {
|
void EnvFake::unset (std::string_view name) noexcept {
|
||||||
|
@ -121,7 +124,8 @@ auto EnvFake::size() const noexcept -> size_type {
|
||||||
return m_map.size();
|
return m_map.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvFake::clear() noexcept {
|
void EnvFake::clear_implem(Mutex& m) {
|
||||||
|
std::lock_guard<Mutex> lock(m);
|
||||||
m_map.clear();
|
m_map.clear();
|
||||||
m_map_strong_cpy.clear();
|
m_map_strong_cpy.clear();
|
||||||
}
|
}
|
||||||
|
@ -141,4 +145,22 @@ auto EnvFake::end() const -> const_iterator {
|
||||||
auto EnvFake::cend() const -> const_iterator {
|
auto EnvFake::cend() const -> const_iterator {
|
||||||
return m_map.cend();
|
return m_map.cend();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::mutex& EnvFake::mutex() noexcept {
|
||||||
|
return m_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvFake::set_all_into (EnvBase& other) const {
|
||||||
|
std::scoped_lock lock(m_mutex, other.mutex());
|
||||||
|
|
||||||
|
EnvBase::clear_nolock(other);
|
||||||
|
for (const auto& keyval : *this) {
|
||||||
|
EnvBase::set_nolock(other, keyval.first, keyval.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EnvFake& EnvFake::operator= (const EnvBase& other) {
|
||||||
|
EnvBase::set_all_into(other, *this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "env_base.hpp"
|
#include "env_base.hpp"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace duck {
|
namespace duck {
|
||||||
class EnvFake : public EnvBase {
|
class EnvFake : public EnvBase {
|
||||||
|
@ -30,21 +31,29 @@ namespace duck {
|
||||||
explicit EnvFake (bool starts_empty=false);
|
explicit EnvFake (bool starts_empty=false);
|
||||||
~EnvFake() noexcept = default;
|
~EnvFake() noexcept = default;
|
||||||
|
|
||||||
|
EnvFake& operator= (const EnvBase& other);
|
||||||
|
|
||||||
virtual std::optional<std::string_view> get (std::string_view name) const noexcept override;
|
virtual std::optional<std::string_view> get (std::string_view name) const noexcept override;
|
||||||
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
|
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
|
||||||
virtual void set (std::string_view name, std::string_view value) override;
|
|
||||||
virtual void unset (std::string_view name) noexcept override;
|
virtual void unset (std::string_view name) noexcept override;
|
||||||
virtual bool is_set (std::string_view name) const noexcept override;
|
virtual bool is_set (std::string_view name) const noexcept override;
|
||||||
virtual size_type size() const noexcept override;
|
virtual size_type size() const noexcept override;
|
||||||
virtual void clear() noexcept override;
|
|
||||||
|
|
||||||
const_iterator begin() const;
|
const_iterator begin() const;
|
||||||
const_iterator cbegin() const;
|
const_iterator cbegin() const;
|
||||||
const_iterator end() const;
|
const_iterator end() const;
|
||||||
const_iterator cend() const;
|
const_iterator cend() const;
|
||||||
|
|
||||||
|
virtual std::mutex& mutex() noexcept override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void set_all_into (EnvBase& other) const override;
|
||||||
|
virtual void clear_implem(Mutex& m) override;
|
||||||
|
virtual void set_implem (std::string_view name, std::string_view value, Mutex& m) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string_view, std::unique_ptr<char[]>> m_map_strong_cpy;
|
std::unordered_map<std::string_view, std::unique_ptr<char[]>> m_map_strong_cpy;
|
||||||
map_type m_map;
|
map_type m_map;
|
||||||
|
mutable std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -40,10 +40,10 @@ namespace {
|
||||||
|
|
||||||
const constexpr std::size_t g_name_buff_len = 128;
|
const constexpr std::size_t g_name_buff_len = 128;
|
||||||
|
|
||||||
PointerMap& pointer_map();
|
PointerMap& pointer_map() noexcept;
|
||||||
|
|
||||||
class PointerMap {
|
class PointerMap {
|
||||||
friend PointerMap& pointer_map();
|
friend PointerMap& pointer_map() noexcept;
|
||||||
public:
|
public:
|
||||||
PointerMap (const PointerMap&) = delete;
|
PointerMap (const PointerMap&) = delete;
|
||||||
PointerMap (PointerMap&&) = delete;
|
PointerMap (PointerMap&&) = delete;
|
||||||
|
@ -70,7 +70,7 @@ namespace {
|
||||||
static void value() noexcept {}
|
static void value() noexcept {}
|
||||||
};
|
};
|
||||||
|
|
||||||
PointerMap& pointer_map() {
|
PointerMap& pointer_map() noexcept {
|
||||||
static PointerMap pm;
|
static PointerMap pm;
|
||||||
return pm;
|
return pm;
|
||||||
}
|
}
|
||||||
|
@ -204,6 +204,11 @@ EnvReal::EnvReal() :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnvReal& EnvReal::operator= (const EnvBase& other) {
|
||||||
|
EnvBase::set_all_into(other, *this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::string_view> EnvReal::get (std::string_view name) const noexcept {
|
std::optional<std::string_view> EnvReal::get (std::string_view name) const noexcept {
|
||||||
const char* const ret = this->raw_fetch_env(name);
|
const char* const ret = this->raw_fetch_env(name);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -220,7 +225,7 @@ std::string_view EnvReal::get (std::string_view name, std::string_view def) cons
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvReal::set (std::string_view name, std::string_view value) {
|
void EnvReal::set_implem (std::string_view name, std::string_view value, Mutex& m) {
|
||||||
assert(not name.empty());
|
assert(not name.empty());
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -236,7 +241,7 @@ void EnvReal::set (std::string_view name, std::string_view value) {
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& pm = pointer_map();
|
auto& pm = pointer_map();
|
||||||
std::lock_guard<std::mutex> lock(pm.env_mutex());
|
std::lock_guard<Mutex> lock(m);
|
||||||
putenv(pm.register_pointer(std::move(new_var)));
|
putenv(pm.register_pointer(std::move(new_var)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,9 +277,9 @@ auto EnvReal::size() const noexcept -> size_type {
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvReal::clear() noexcept {
|
void EnvReal::clear_implem(Mutex& m) {
|
||||||
auto& pm = pointer_map();
|
auto& pm = pointer_map();
|
||||||
std::lock_guard<std::mutex> lock(pm.env_mutex());
|
std::lock_guard<Mutex> lock(m);
|
||||||
const int r = clearenv();
|
const int r = clearenv();
|
||||||
if (not r) {
|
if (not r) {
|
||||||
pm.clear();
|
pm.clear();
|
||||||
|
@ -315,4 +320,18 @@ auto EnvReal::cend() const -> const_iterator {
|
||||||
assert(*(::environ + this->size()) == nullptr);
|
assert(*(::environ + this->size()) == nullptr);
|
||||||
return {::environ + this->size()};
|
return {::environ + this->size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::mutex& EnvReal::mutex() noexcept {
|
||||||
|
return pointer_map().env_mutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvReal::set_all_into (EnvBase& other) const {
|
||||||
|
auto& pm = pointer_map();
|
||||||
|
std::scoped_lock lock(pm.env_mutex(), other.mutex());
|
||||||
|
|
||||||
|
EnvBase::clear_nolock(other);
|
||||||
|
for (const auto& keyval : *this) {
|
||||||
|
EnvBase::set_nolock(other, keyval.first, keyval.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -52,19 +52,26 @@ namespace duck {
|
||||||
EnvReal();
|
EnvReal();
|
||||||
virtual ~EnvReal() noexcept = default;
|
virtual ~EnvReal() noexcept = default;
|
||||||
|
|
||||||
|
EnvReal& operator= (const EnvBase& other);
|
||||||
|
|
||||||
virtual std::optional<std::string_view> get (std::string_view name) const noexcept override;
|
virtual std::optional<std::string_view> get (std::string_view name) const noexcept override;
|
||||||
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
|
virtual std::string_view get (std::string_view name, std::string_view def) const noexcept override;
|
||||||
virtual void set (std::string_view name, std::string_view value) override;
|
|
||||||
virtual void unset (std::string_view name) noexcept override;
|
virtual void unset (std::string_view name) noexcept override;
|
||||||
virtual bool is_set (std::string_view name) const noexcept override;
|
virtual bool is_set (std::string_view name) const noexcept override;
|
||||||
virtual size_type size() const noexcept override;
|
virtual size_type size() const noexcept override;
|
||||||
virtual void clear() noexcept override;
|
|
||||||
|
|
||||||
const_iterator begin() const;
|
const_iterator begin() const;
|
||||||
const_iterator cbegin() const;
|
const_iterator cbegin() const;
|
||||||
const_iterator end() const;
|
const_iterator end() const;
|
||||||
const_iterator cend() const;
|
const_iterator cend() const;
|
||||||
|
|
||||||
|
virtual std::mutex& mutex() noexcept override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void set_all_into (EnvBase& other) const override;
|
||||||
|
virtual void clear_implem(Mutex& m) override;
|
||||||
|
virtual void set_implem (std::string_view name, std::string_view value, Mutex& m) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char* raw_fetch_env (std::string_view name) const noexcept;
|
const char* raw_fetch_env (std::string_view name) const noexcept;
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,29 @@
|
||||||
namespace duck {
|
namespace duck {
|
||||||
void safe_print (std::string_view msg) noexcept {
|
void safe_print (std::string_view msg) noexcept {
|
||||||
try {
|
try {
|
||||||
std::cout << msg << std::endl;
|
std::cout << msg;
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void safe_print_error (std::string_view msg) noexcept {
|
void safe_print_error (std::string_view msg) noexcept {
|
||||||
|
try {
|
||||||
|
std::cerr << msg;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void safe_print_ln (std::string_view msg) noexcept {
|
||||||
|
try {
|
||||||
|
std::cout << msg << std::endl;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void safe_print_error_ln (std::string_view msg) noexcept {
|
||||||
try {
|
try {
|
||||||
std::cerr << msg << std::endl;
|
std::cerr << msg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,7 @@
|
||||||
namespace duck {
|
namespace duck {
|
||||||
void safe_print (std::string_view msg) noexcept;
|
void safe_print (std::string_view msg) noexcept;
|
||||||
void safe_print_error (std::string_view msg) noexcept;
|
void safe_print_error (std::string_view msg) noexcept;
|
||||||
|
|
||||||
|
void safe_print_ln (std::string_view msg) noexcept;
|
||||||
|
void safe_print_error_ln (std::string_view msg) noexcept;
|
||||||
} //namespace duck
|
} //namespace duck
|
||||||
|
|
|
@ -37,6 +37,11 @@ namespace duck {
|
||||||
return (str ? std::string_view{str} : std::string_view{""});
|
return (str ? std::string_view{str} : std::string_view{""});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <std::size_t S>
|
||||||
|
inline std::string_view to_string_view (const char (&str)[S]) noexcept {
|
||||||
|
return std::string_view(str, S);
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string operator+ (std::string_view a, std::string_view b) {
|
inline std::string operator+ (std::string_view a, std::string_view b) {
|
||||||
std::string ret(to_string(a));
|
std::string ret(to_string(a));
|
||||||
ret += b;
|
ret += b;
|
||||||
|
|
Loading…
Reference in a new issue