Skip to content

Commit 6c44fcb

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

File tree

6 files changed

+108
-40
lines changed

6 files changed

+108
-40
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+
Mod const& 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: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
#pragma once
22

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

88
#include <fmt/base.h>
99

10-
#include "openvic-simulation/types/Colour.hpp"
1110
#include "openvic-simulation/core/template/Concepts.hpp"
11+
#include "openvic-simulation/types/Colour.hpp"
1212
#include "openvic-simulation/utility/Getters.hpp"
1313

1414
namespace OpenVic {
@@ -30,6 +30,12 @@ namespace OpenVic {
3030
HasIdentifier(HasIdentifier&&) = default;
3131
HasIdentifier& operator=(HasIdentifier const&) = delete;
3232
HasIdentifier& operator=(HasIdentifier&&) = delete;
33+
34+
template <std::derived_from<HasIdentifier> T>
35+
requires (!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<OpenVic::has_get_identifier T>
108+
requires (!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: 11 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,13 @@ namespace OpenVic {
2628
return index == rhs.index;
2729
}
2830
};
31+
}
32+
33+
namespace std {
34+
template<OpenVic::has_index T>
35+
struct hash<T> {
36+
[[nodiscard]] std::size_t operator()(T const& obj) const noexcept {
37+
return std::hash<typename T::index_t>{}(obj.index);
38+
}
39+
};
2940
}

src/openvic-simulation/types/OrderedContainers.hpp

Lines changed: 43 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,18 @@
1416
#include <foonathan/memory/default_allocator.hpp>
1517
#include <foonathan/memory/std_allocator.hpp>
1618

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

4885
// Useful for contiguous memory
4986
template<
50-
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
87+
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
5188
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
5289
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
5390
using vector_ordered_map =
5491
tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, std::vector<std::pair<Key, T>, Allocator>, IndexType>;
5592

5693
// Useful for stable memory addresses (so long as you don't remove or insert values)
5794
template<
58-
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
95+
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
5996
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
6097
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
6198
using deque_ordered_map =
6299
tsl::ordered_map<Key, T, Hash, KeyEqual, Allocator, OpenVic::utility::deque<std::pair<Key, T>, Allocator>, IndexType>;
63100

64101
template<
65-
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
102+
class Key, class T, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
66103
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
67104
class Allocator = foonathan::memory::std_allocator<std::pair<Key, T>, memory::tracker<RawAllocator>>>
68105
using ordered_map = vector_ordered_map<Key, T, Hash, KeyEqual, RawAllocator, IndexType, Allocator>;
69106

70107
// Useful for contiguous memory
71108
template<
72-
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
109+
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
73110
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
74111
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
75112
using vector_ordered_set = tsl::ordered_set<Key, Hash, KeyEqual, Allocator, std::vector<Key, Allocator>, IndexType>;
76113

77114
// Useful for stable memory addresses (so long as you don't remove or insert values)
78115
template<
79-
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
116+
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
80117
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
81118
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
82119
using deque_ordered_set =
83120
tsl::ordered_set<Key, Hash, KeyEqual, Allocator, OpenVic::utility::deque<Key, Allocator>, IndexType>;
84121

85122
template<
86-
class Key, class Hash = container_hash<Key>, class KeyEqual = std::equal_to<>,
123+
class Key, class Hash = container_hash<Key>, class KeyEqual = default_equal_to<Key>,
87124
class RawAllocator = foonathan::memory::default_allocator, class IndexType = std::uint_least32_t,
88125
class Allocator = foonathan::memory::std_allocator<Key, memory::tracker<RawAllocator>>>
89126
using ordered_set = vector_ordered_set<Key, Hash, KeyEqual, RawAllocator, IndexType, Allocator>;

0 commit comments

Comments
 (0)