/* Copyright 2020, Michele Santullo * This file is part of user-gcc. * * User-gcc is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * User-gcc is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with user-gcc. If not, see . */ #include "env_fake.hpp" #include "to_var_map.hpp" #include "safe_print.hpp" #include "string_view_cat.hpp" #include #include #include #include #include #include namespace duck { namespace { template < typename M, typename I, typename F, typename R=decltype(std::declval()(std::declval().find(std::declval()))&>())), //not supposed to be altered by the caller bool FIsNoex=noexcept(std::declval()(std::declval().find(std::declval()))&>())) and noexcept(R()) > R run_if_found (M& map, const I& item, F func) noexcept(FIsNoex) { typedef decltype(map.find(item)) iterator_type; iterator_type it_found; if constexpr (FIsNoex) { try { it_found = map.find(item); } catch (...) { safe_print_error("Unexpected exception in run_if_found() will be ignored"); } } else { it_found = map.find(item); } if constexpr (std::is_same::value) { if (map.end() != it_found) { func(it_found); } } else { if (map.end() != it_found) { return func(it_found); } else { return R{}; } } } } //unnamed namespace EnvFake::EnvFake (bool starts_empty) : m_map_strong_cpy(), m_map(starts_empty ? map_type() : to_var_map_ignore_ownership(environ)) { } std::optional EnvFake::get (std::string_view name) const noexcept { return run_if_found(m_map, name, [](auto& it)noexcept{return std::make_optional(it->second);}); } std::string_view EnvFake::get (std::string_view name, std::string_view def) const noexcept { bool ret_def{true}; std::string_view maybe_ret(run_if_found(m_map, name, [&ret_def](auto& it)noexcept{ret_def=false; return it->second;})); if (ret_def) return def; else return maybe_ret; } void EnvFake::set_implem (std::string_view name, std::string_view value, Mutex& m) { assert(not name.empty()); if (name.empty()) return; const std::size_t size = name.size() + value.size(); std::unique_ptr buff = std::make_unique(size); std::copy(name.begin(), name.end(), buff.get()); std::copy(value.begin(), value.end(), buff.get() + name.size()); const std::string_view new_name(buff.get(), name.size()); assert(new_name == name); const std::string_view new_value(buff.get() + name.size(), value.size()); assert(new_value == value); { std::lock_guard lock(m); 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)); assert(m_map.at(name) == value); assert(m_map.find(name)->first.data() == new_name.data()); } } void EnvFake::unset_implem (std::string_view name, Mutex& m) { std::lock_guard lock(m); run_if_found(m_map, name, [&](auto& it)noexcept{m_map.erase(it);}); run_if_found(m_map_strong_cpy, name, [&](auto& it)noexcept{m_map_strong_cpy.erase(it);}); } bool EnvFake::is_set_implem (std::string_view name, Mutex& m) const { std::lock_guard lock(m); return run_if_found(m_map, name, [](auto&)noexcept{return true;}); } auto EnvFake::size_implem (Mutex& m) const -> size_type { std::lock_guard lock(m); return m_map.size(); } void EnvFake::clear_implem(Mutex& m) { std::lock_guard lock(m); m_map.clear(); m_map_strong_cpy.clear(); } auto EnvFake::begin() const -> const_iterator { return m_map.cbegin(); } auto EnvFake::cbegin() const -> const_iterator { return m_map.cbegin(); } auto EnvFake::end() const -> const_iterator { return m_map.cend(); } auto EnvFake::cend() const -> const_iterator { return m_map.cend(); } std::mutex& EnvFake::mutex() const 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