Skip to content

Commit 1e907d9

Browse files
committed
std::reference_wrapper demo
1 parent 0a08ff2 commit 1e907d9

File tree

6 files changed

+109
-39
lines changed

6 files changed

+109
-39
lines changed

src/openvic-simulation/GameManager.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "GameManager.hpp"
22

33
#include <chrono>
4+
#include <functional>
45
#include <string_view>
56

67
#include <range/v3/algorithm/contains.hpp>
@@ -76,7 +77,7 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
7677

7778
bool ret = true;
7879

79-
vector_ordered_set<Mod const*> load_list;
80+
vector_ordered_set<std::reference_wrapper<const Mod>> load_list;
8081

8182
/* Check loaded mod descriptors for requested mods, using either full name or user directory name
8283
* (Historical Project Mod 0.4.6 or HPM both valid, for example), and load them plus their dependencies.
@@ -94,8 +95,8 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
9495
continue;
9596
}
9697

97-
Mod const* mod_ptr = &*it;
98-
vector_ordered_set<Mod const*> dependencies = mod_ptr->generate_dependency_list(&ret);
98+
const Mod& mod = *it;
99+
vector_ordered_set<std::reference_wrapper<const Mod>> dependencies = mod.generate_dependency_list(&ret);
99100
if(!ret) {
100101
continue;
101102
}
@@ -104,15 +105,15 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
104105
if (load_list.empty()) {
105106
load_list = std::move(dependencies);
106107
} else {
107-
for (Mod const* dep : dependencies) {
108+
for (Mod const& dep : dependencies) {
108109
if (!load_list.contains(dep)) {
109110
load_list.emplace(dep);
110111
}
111112
}
112113
}
113114

114-
if (!load_list.contains(mod_ptr)) {
115-
load_list.emplace(mod_ptr);
115+
if (!load_list.contains(mod)) {
116+
load_list.emplace(mod);
116117
}
117118
}
118119

@@ -122,9 +123,9 @@ bool GameManager::load_mods(memory::vector<memory::string> const& mods_to_find)
122123
vector_ordered_set<fs::path> replace_paths;
123124

124125
/* Actually registers all roots and replace paths to be loaded by the game. */
125-
for (Mod const* mod : load_list) {
126-
roots.emplace_back(roots[0] / mod->get_dataloader_root_path());
127-
for (std::string_view path : mod->get_replace_paths()) {
126+
for (Mod const& mod : load_list) {
127+
roots.emplace_back(roots[0] / mod.get_dataloader_root_path());
128+
for (std::string_view path : mod.get_replace_paths()) {
128129
replace_paths.emplace(path);
129130
}
130131
}

src/openvic-simulation/dataloader/ModManager.cpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#include "ModManager.hpp"
22

3+
#include <functional>
34
#include <string_view>
45

56
#include "openvic-simulation/core/error/ErrorMacros.hpp"
67
#include "openvic-simulation/dataloader/NodeTools.hpp"
78
#include "openvic-simulation/types/HasIdentifier.hpp"
89
#include "openvic-simulation/types/IdentifierRegistry.hpp"
910
#include "openvic-simulation/types/OrderedContainers.hpp"
10-
#include "openvic-simulation/core/FormatValidate.hpp"
1111

1212
using namespace OpenVic;
1313
using namespace OpenVic::NodeTools;
@@ -27,42 +27,48 @@ Mod::Mod(
2727
replace_paths { new_replace_paths },
2828
dependencies { new_dependencies } {}
2929

30-
vector_ordered_set<Mod const*> Mod::generate_dependency_list(bool* success) const {
30+
vector_ordered_set<std::reference_wrapper<const Mod>> Mod::generate_dependency_list(bool* success) const {
3131
static constexpr size_t MAX_RECURSE = 16;
3232
size_t current_recurse = 0;
3333

34-
vector_ordered_set<Mod const*> result;
34+
vector_ordered_set<std::reference_wrapper<const Mod>> result;
3535

36-
auto dep_cycle = [this, &current_recurse](auto self, Mod const* mod, vector_ordered_set<Mod const*>& dep_list) -> bool {
36+
auto dep_cycle = [this, &current_recurse](
37+
auto self,
38+
Mod const& mod,
39+
vector_ordered_set<std::reference_wrapper<const Mod>>& dep_list
40+
) -> bool {
3741
bool ret = true;
38-
for (std::string_view dep_identifier : mod->get_dependencies()) {
39-
if (!mod_manager.has_mod_identifier(dep_identifier)) {
42+
for (std::string_view dep_identifier : mod.get_dependencies()) {
43+
Mod const* dep_ptr = mod_manager.get_mod_by_identifier(dep_identifier);
44+
if (dep_ptr == nullptr) {
4045
spdlog::error_s(
4146
"Mod \"{}\" has unmet dependency \"{}\" and cannot be loaded!",
42-
ovfmt::validate(mod), dep_identifier
47+
mod, dep_identifier
4348
);
4449
return false;
4550
}
46-
Mod const* dep = mod_manager.get_mod_by_identifier(dep_identifier);
51+
Mod const& dep = *dep_ptr;
4752
/* The poor man's cycle checking (cycles should be very rare and hard to accomplish with vic2 modding, this is a failsafe) */
4853
if (current_recurse == MAX_RECURSE) {
4954
spdlog::error_s(
5055
"Mod \"{}\" has cyclical or broken dependency chain and cannot be loaded!",
51-
ovfmt::validate(mod)
56+
mod
5257
);
5358
return false;
5459
} else {
5560
current_recurse++;
5661
ret &= self(self, dep, dep_list); /* recursively search for mod dependencies */
5762
}
63+
5864
if (!dep_list.contains(dep)) {
59-
dep_list.emplace(dep);
65+
dep_list.insert(dep);
6066
}
6167
}
6268
return ret;
6369
};
6470

65-
bool loaded_deps = dep_cycle(dep_cycle, this, result);
71+
bool loaded_deps = dep_cycle(dep_cycle, *this, result);
6672
if (success) {
6773
*success = loaded_deps;
6874
}
@@ -100,20 +106,16 @@ bool ModManager::load_mod_file(ast::NodeCPtr root) {
100106
return true;
101107
}
102108

103-
void ModManager::set_loaded_mods(memory::vector<Mod const*>&& new_loaded_mods) {
109+
void ModManager::set_loaded_mods(memory::vector<std::reference_wrapper<const Mod>>&& new_loaded_mods) {
104110
OV_ERR_FAIL_COND_MSG(mods_loaded, "set_loaded_mods called twice");
105111

106112
loaded_mods = std::move(new_loaded_mods);
107113
mods_loaded = true;
108-
for (Mod const* mod : loaded_mods) {
109-
SPDLOG_INFO("Loading mod \"{}\" at path {}", *mod, mod->get_dataloader_root_path());
114+
for (Mod const& mod : loaded_mods) {
115+
SPDLOG_INFO("Loading mod \"{}\" at path {}", mod, mod.get_dataloader_root_path());
110116
}
111117
}
112118

113-
memory::vector<Mod const*> const& ModManager::get_loaded_mods() const {
114-
return loaded_mods;
115-
}
116-
117119
size_t ModManager::get_loaded_mod_count() const {
118120
return loaded_mods.size();
119121
}

src/openvic-simulation/dataloader/ModManager.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#pragma once
22

33
#include <cstddef>
4+
#include <functional>
45
#include <string_view>
56

67
#include "openvic-simulation/types/HasIdentifier.hpp"
78
#include "openvic-simulation/types/IdentifierRegistry.hpp"
89
#include "openvic-simulation/dataloader/NodeTools.hpp"
10+
#include "openvic-simulation/utility/Getters.hpp"
911

1012
namespace OpenVic {
1113
struct ModManager;
@@ -32,22 +34,21 @@ namespace OpenVic {
3234
);
3335
Mod(Mod&&) = default;
3436

35-
vector_ordered_set<Mod const*> generate_dependency_list(bool* success = nullptr) const;
37+
vector_ordered_set<std::reference_wrapper<const Mod>> generate_dependency_list(bool* success = nullptr) const;
3638
};
3739

3840
struct ModManager {
3941

4042
private:
4143
IdentifierRegistry<Mod> IDENTIFIER_REGISTRY(mod);
42-
memory::vector<Mod const*> loaded_mods;
44+
memory::vector<std::reference_wrapper<const Mod>> SPAN_PROPERTY(loaded_mods);
4345
bool mods_loaded = false;
4446

4547
public:
4648
ModManager();
4749

4850
bool load_mod_file(ast::NodeCPtr root);
49-
void set_loaded_mods(memory::vector<Mod const*>&& new_loaded_mods);
50-
memory::vector<Mod const*> const& get_loaded_mods() const;
51+
void set_loaded_mods(memory::vector<std::reference_wrapper<const Mod>>&& new_loaded_mods);
5152
size_t get_loaded_mod_count() const;
5253
};
5354
}

src/openvic-simulation/types/HasIdentifier.hpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#pragma once
22

3-
#include <algorithm>
43
#include <cassert>
4+
#include <cstddef>
55
#include <string_view>
66
#include <ostream>
77

@@ -30,6 +30,12 @@ namespace OpenVic {
3030
HasIdentifier(HasIdentifier&&) = default;
3131
HasIdentifier& operator=(HasIdentifier const&) = delete;
3232
HasIdentifier& operator=(HasIdentifier&&) = delete;
33+
34+
template <typename T>
35+
requires std::derived_from<T, HasIdentifier> && (!has_index<T>)
36+
friend bool operator==(T const& lhs, T const& rhs) {
37+
return lhs.get_identifier() == rhs.get_identifier();
38+
}
3339
};
3440

3541
inline std::ostream& operator<<(std::ostream& stream, HasIdentifier const& obj) {
@@ -95,4 +101,14 @@ struct fmt::formatter<T> : fmt::formatter<fmt::string_view> {
95101
fmt::format_context::iterator format(T const& has_id, fmt::format_context& ctx) const {
96102
return fmt::formatter<fmt::string_view>::format(has_id.get_name(), ctx);
97103
}
98-
};
104+
};
105+
106+
namespace std {
107+
template<typename T>
108+
requires OpenVic::has_get_identifier<T> && (!OpenVic::has_index<T>)
109+
struct hash<T> {
110+
[[nodiscard]] std::size_t operator()(T const& obj) const noexcept {
111+
return std::hash<std::string_view>{}(obj.get_identifier());
112+
}
113+
};
114+
}

src/openvic-simulation/types/HasIndex.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include <cstddef>
4+
35
#include <type_safe/strong_typedef.hpp>
46

57
#include "openvic-simulation/core/template/Concepts.hpp"
@@ -26,4 +28,14 @@ namespace OpenVic {
2628
return index == rhs.index;
2729
}
2830
};
31+
}
32+
33+
namespace std {
34+
template<typename T>
35+
requires OpenVic::has_index<T>
36+
struct hash<T> {
37+
[[nodiscard]] std::size_t operator()(T const& obj) const noexcept {
38+
return std::hash<typename T::index_t>{}(obj.index);
39+
}
40+
};
2941
}

src/openvic-simulation/types/OrderedContainers.hpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#pragma once
22

33
#include <cctype>
4+
#include <cstddef>
45
#include <functional>
6+
#include <type_traits>
57

68
#include <tsl/ordered_map.h>
79
#include <tsl/ordered_set.h>
@@ -14,6 +16,19 @@
1416
#include <foonathan/memory/default_allocator.hpp>
1517
#include <foonathan/memory/std_allocator.hpp>
1618

19+
//pre c++ 26
20+
namespace std {
21+
template<typename T>
22+
struct equal_to<std::reference_wrapper<const T>> {
23+
[[nodiscard]] bool operator()(
24+
std::reference_wrapper<const T> const& lhs,
25+
std::reference_wrapper<const T> const& rhs
26+
) const noexcept {
27+
return lhs.get() == rhs.get();
28+
}
29+
};
30+
}
31+
1732
namespace OpenVic {
1833
struct ordered_container_string_hash {
1934
using is_transparent = void;
@@ -44,46 +59,69 @@ namespace OpenVic {
4459
struct container_hash<char const*> : ordered_container_string_hash {};
4560
template<typename T>
4661
struct container_hash<T*> : std::hash<T const*> {};
62+
template<typename T>
63+
struct container_hash<std::reference_wrapper<T>> : std::hash<const T> {};
64+
template<typename T>
65+
struct container_hash<std::reference_wrapper<const T>> : std::hash<const T> {};
66+
67+
// Default: Use transparent equality
68+
template<typename T>
69+
struct default_equal_to_selector {
70+
using type = std::equal_to<>;
71+
};
72+
73+
// Specialization for reference_wrapper
74+
template<typename T>
75+
struct default_equal_to_selector<std::reference_wrapper<T>> {
76+
using type = std::equal_to<std::reference_wrapper<const T>>;
77+
};
78+
template<typename T>
79+
struct default_equal_to_selector<std::reference_wrapper<const T>> {
80+
using type = std::equal_to<std::reference_wrapper<const T>>;
81+
};
82+
83+
template<typename T>
84+
using default_equal_to = typename default_equal_to_selector<T>::type;
4785

4886
// Useful for contiguous memory
4987
template<
50-
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
88+
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
5189
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
5290
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
5391
using vector_ordered_map =
5492
tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, std::vector<std::pair<Key, T>, Allocator>, IndexType>;
5593

5694
// Useful for stable memory addresses (so long as you don't remove or insert values)
5795
template<
58-
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
96+
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
5997
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
6098
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
6199
using deque_ordered_map =
62100
tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, OpenVic::utility::deque<std::pair<Key, T>, Allocator>, IndexType>;
63101

64102
template<
65-
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
103+
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
66104
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
67105
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
68106
using ordered_map = vector_ordered_map<Key, T, Hash, KeyEqual, RawAllocator, IndexType, Allocator>;
69107

70108
// Useful for contiguous memory
71109
template<
72-
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
110+
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
73111
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
74112
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
75113
using vector_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::vector<Key, Allocator>, IndexType>;
76114

77115
// Useful for stable memory addresses (so long as you don't remove or insert values)
78116
template<
79-
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
117+
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
80118
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
81119
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
82120
using deque_ordered_set =
83121
tsl::ordered_set<Key, Hash, KeyEqual, Allocator, OpenVic::utility::deque<Key, Allocator>, IndexType>;
84122

85123
template<
86-
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
124+
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
87125
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
88126
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
89127
using ordered_set = vector_ordered_set<Key, Hash, KeyEqual, RawAllocator, IndexType, Allocator>;

0 commit comments

Comments
 (0)