Skip to content

Commit d20f458

Browse files
committed
Convert player ownership model to shared_ptr
1 parent edbe2e6 commit d20f458

11 files changed

Lines changed: 188 additions & 54 deletions

File tree

src/games/game.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace Gambit {
4242
GameOutcomeRep::GameOutcomeRep(GameRep *p_game, int p_number) : m_game(p_game), m_number(p_number)
4343
{
4444
for (const auto &player : m_game->m_players) {
45-
m_payoffs[player] = Number();
45+
m_payoffs[player.get()] = Number();
4646
}
4747
}
4848

@@ -52,7 +52,7 @@ GameOutcomeRep::GameOutcomeRep(GameRep *p_game, int p_number) : m_game(p_game),
5252

5353
GameAction GameStrategyRep::GetAction(const GameInfoset &p_infoset) const
5454
{
55-
if (p_infoset->GetPlayer() != m_player) {
55+
if (p_infoset->GetPlayer().get() != m_player) {
5656
throw MismatchException();
5757
}
5858
const int action = m_behav[p_infoset->GetNumber()];
@@ -366,7 +366,7 @@ MixedStrategyProfile<T>::operator=(const MixedStrategyProfile<T> &p_profile)
366366
// MixedStrategyProfile<T>: General data access
367367
//========================================================================
368368

369-
template <class T> Vector<T> MixedStrategyProfile<T>::operator[](const GamePlayer &p_player) const
369+
template <class T> Vector<T> MixedStrategyProfile<T>::GetStrategy(const GamePlayer &p_player) const
370370
{
371371
CheckVersion();
372372
auto strategies = m_rep->m_support.GetStrategies(p_player);

src/games/game.h

Lines changed: 104 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class GameStrategyRep;
4949
using GameStrategy = GameObjectPtr<GameStrategyRep>;
5050

5151
class GamePlayerRep;
52-
using GamePlayer = GameObjectPtr<GamePlayerRep>;
52+
using GamePlayer = GameObjectSmartPtr<GamePlayerRep>;
5353

5454
class GameNodeRep;
5555
using GameNode = GameObjectPtr<GameNodeRep>;
@@ -132,6 +132,81 @@ template <class P, class T> class ElementCollection {
132132
iterator cend() const { return {m_owner, m_container, (m_owner) ? m_container->size() : 0}; }
133133
};
134134

135+
template <class P, class T> class SmartElementCollection {
136+
P m_owner{nullptr};
137+
const std::vector<std::shared_ptr<T>> *m_container{nullptr};
138+
139+
public:
140+
class iterator {
141+
P m_owner{nullptr};
142+
const std::vector<std::shared_ptr<T>> *m_container{nullptr};
143+
size_t m_index{0};
144+
145+
public:
146+
using iterator_category = std::bidirectional_iterator_tag;
147+
using difference_type = std::ptrdiff_t;
148+
using value_type = GameObjectSmartPtr<T>;
149+
using pointer = value_type *;
150+
using reference = value_type &;
151+
152+
iterator() = default;
153+
iterator(const P &p_owner, const std::vector<std::shared_ptr<T>> *p_container,
154+
size_t p_index = 0)
155+
: m_owner(p_owner), m_container(p_container), m_index(p_index)
156+
{
157+
}
158+
iterator(const iterator &) = default;
159+
~iterator() = default;
160+
iterator &operator=(const iterator &) = default;
161+
162+
bool operator==(const iterator &p_iter) const
163+
{
164+
return m_owner == p_iter.m_owner && m_container == p_iter.m_container &&
165+
m_index == p_iter.m_index;
166+
}
167+
bool operator!=(const iterator &p_iter) const
168+
{
169+
return m_owner != p_iter.m_owner || m_container != p_iter.m_container ||
170+
m_index != p_iter.m_index;
171+
}
172+
173+
iterator &operator++()
174+
{
175+
m_index++;
176+
return *this;
177+
}
178+
iterator &operator--()
179+
{
180+
m_index--;
181+
return *this;
182+
}
183+
value_type operator*() const { return m_container->at(m_index); }
184+
};
185+
186+
SmartElementCollection() = default;
187+
explicit SmartElementCollection(const P &p_owner,
188+
const std::vector<std::shared_ptr<T>> *p_container)
189+
: m_owner(p_owner), m_container(p_container)
190+
{
191+
}
192+
SmartElementCollection(const SmartElementCollection<P, T> &) = default;
193+
~SmartElementCollection() = default;
194+
SmartElementCollection &operator=(const SmartElementCollection<P, T> &) = default;
195+
196+
bool operator==(const SmartElementCollection<P, T> &p_other) const
197+
{
198+
return m_owner == p_other.m_owner && m_container == p_other.m_container;
199+
}
200+
size_t size() const { return m_container->size(); }
201+
GameObjectSmartPtr<T> front() const { return m_container->front(); }
202+
GameObjectSmartPtr<T> back() const { return m_container->back(); }
203+
204+
iterator begin() const { return {m_owner, m_container, 0}; }
205+
iterator end() const { return {m_owner, m_container, (m_owner) ? m_container->size() : 0}; }
206+
iterator cbegin() const { return {m_owner, m_container, 0}; }
207+
iterator cend() const { return {m_owner, m_container, (m_owner) ? m_container->size() : 0}; }
208+
};
209+
135210
//
136211
// Forward declarations of classes defined elsewhere.
137212
//
@@ -369,7 +444,7 @@ class GameStrategyRep : public GameObject {
369444
};
370445

371446
/// A player in a game
372-
class GamePlayerRep : public GameObject {
447+
class GamePlayerRep : public std::enable_shared_from_this<GamePlayerRep> {
373448
friend class GameRep;
374449
friend class GameExplicitRep;
375450
friend class GameTreeRep;
@@ -388,20 +463,24 @@ class GamePlayerRep : public GameObject {
388463
void MakeReducedStrats(class GameNodeRep *, class GameNodeRep *);
389464
//@}
390465

466+
bool m_valid{true};
391467
GameRep *m_game;
392468
int m_number;
393469
std::string m_label;
394470
std::vector<GameInfosetRep *> m_infosets;
395471
std::vector<GameStrategyRep *> m_strategies;
396472

397-
GamePlayerRep(GameRep *p_game, int p_id) : m_game(p_game), m_number(p_id) {}
398-
GamePlayerRep(GameRep *p_game, int p_id, int m_strats);
399-
~GamePlayerRep() override;
400-
401473
public:
402474
using Infosets = ElementCollection<GamePlayer, GameInfosetRep>;
403475
using Strategies = ElementCollection<GamePlayer, GameStrategyRep>;
404476

477+
GamePlayerRep(GameRep *p_game, int p_id) : m_game(p_game), m_number(p_id) {}
478+
GamePlayerRep(GameRep *p_game, int p_id, int m_strats);
479+
~GamePlayerRep();
480+
481+
bool IsValid() const { return m_valid; }
482+
void Invalidate() { m_valid = false; }
483+
405484
int GetNumber() const { return m_number; }
406485
Game GetGame() const;
407486

@@ -415,7 +494,10 @@ class GamePlayerRep : public GameObject {
415494
/// Returns the p_index'th information set
416495
GameInfoset GetInfoset(int p_index) const { return m_infosets.at(p_index - 1); }
417496
/// Returns the information sets for the player
418-
Infosets GetInfosets() const { return Infosets(this, &m_infosets); }
497+
Infosets GetInfosets() const
498+
{
499+
return Infosets(std::const_pointer_cast<GamePlayerRep>(shared_from_this()), &m_infosets);
500+
}
419501

420502
/// @name Strategies
421503
//@{
@@ -499,7 +581,7 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
499581
template <class T> friend class TableMixedStrategyProfileRep;
500582

501583
protected:
502-
std::vector<GamePlayerRep *> m_players;
584+
std::vector<std::shared_ptr<GamePlayerRep>> m_players;
503585
std::vector<GameOutcomeRep *> m_outcomes;
504586
std::string m_title, m_comment;
505587
unsigned int m_version{0};
@@ -513,7 +595,7 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
513595
//@}
514596

515597
public:
516-
using Players = ElementCollection<Game, GamePlayerRep>;
598+
using Players = SmartElementCollection<Game, GamePlayerRep>;
517599
using Outcomes = ElementCollection<Game, GameOutcomeRep>;
518600

519601
class Nodes {
@@ -728,17 +810,19 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
728810
int NumStrategyContingencies() const
729811
{
730812
BuildComputedValues();
731-
return std::transform_reduce(m_players.begin(), m_players.end(), 0, std::multiplies<>(),
732-
[](const GamePlayerRep *p) { return p->m_strategies.size(); });
813+
return std::transform_reduce(
814+
m_players.begin(), m_players.end(), 0, std::multiplies<>(),
815+
[](const std::shared_ptr<GamePlayerRep> &p) { return p->m_strategies.size(); });
733816
}
734817
/// Returns the total number of actions in the game
735818
virtual int BehavProfileLength() const = 0;
736819
/// Returns the total number of strategies in the game
737820
int MixedProfileLength() const
738821
{
739822
BuildComputedValues();
740-
return std::transform_reduce(m_players.begin(), m_players.end(), 0, std::plus<>(),
741-
[](const GamePlayerRep *p) { return p->m_strategies.size(); });
823+
return std::transform_reduce(
824+
m_players.begin(), m_players.end(), 0, std::plus<>(),
825+
[](const std::shared_ptr<GamePlayerRep> &p) { return p->m_strategies.size(); });
742826
}
743827
//@}
744828

@@ -778,7 +862,7 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
778862
/// Returns the number of players in the game
779863
size_t NumPlayers() const { return m_players.size(); }
780864
/// Returns the pl'th player in the game
781-
GamePlayer GetPlayer(int pl) const { return m_players.at(pl - 1); }
865+
GamePlayer GetPlayer(int pl) const { return m_players.at(pl - 1)->shared_from_this(); }
782866
/// Returns the set of players in the game
783867
Players GetPlayers() const
784868
{
@@ -847,7 +931,7 @@ inline Game GameOutcomeRep::GetGame() const { return m_game->shared_from_this();
847931
template <class T> const T &GameOutcomeRep::GetPayoff(const GamePlayer &p_player) const
848932
{
849933
try {
850-
return static_cast<const T &>(m_payoffs.at(p_player));
934+
return static_cast<const T &>(m_payoffs.at(p_player.get()));
851935
}
852936
catch (const std::out_of_range &) {
853937
throw MismatchException();
@@ -857,7 +941,7 @@ template <class T> const T &GameOutcomeRep::GetPayoff(const GamePlayer &p_player
857941
template <> inline const Number &GameOutcomeRep::GetPayoff(const GamePlayer &p_player) const
858942
{
859943
try {
860-
return m_payoffs.at(p_player);
944+
return m_payoffs.at(p_player.get());
861945
}
862946
catch (const std::out_of_range &) {
863947
throw MismatchException();
@@ -869,14 +953,14 @@ inline void GameOutcomeRep::SetPayoff(const GamePlayer &p_player, const Number &
869953
if (p_player->GetGame() != GetGame()) {
870954
throw MismatchException();
871955
}
872-
m_payoffs[p_player] = p_value;
956+
m_payoffs[p_player.get()] = p_value;
873957
m_game->IncrementVersion();
874958
}
875959

876-
inline GamePlayer GameStrategyRep::GetPlayer() const { return m_player; }
960+
inline GamePlayer GameStrategyRep::GetPlayer() const { return m_player->shared_from_this(); }
877961

878962
inline Game GameInfosetRep::GetGame() const { return m_game->shared_from_this(); }
879-
inline GamePlayer GameInfosetRep::GetPlayer() const { return m_player; }
963+
inline GamePlayer GameInfosetRep::GetPlayer() const { return m_player->shared_from_this(); }
880964
inline bool GameInfosetRep::IsChanceInfoset() const { return m_player->IsChance(); }
881965

882966
inline Game GamePlayerRep::GetGame() const { return m_game->shared_from_this(); }
@@ -888,7 +972,7 @@ inline GameStrategy GamePlayerRep::GetStrategy(int st) const
888972
inline GamePlayerRep::Strategies GamePlayerRep::GetStrategies() const
889973
{
890974
m_game->BuildComputedValues();
891-
return Strategies(this, &m_strategies);
975+
return Strategies(std::const_pointer_cast<GamePlayerRep>(shared_from_this()), &m_strategies);
892976
}
893977

894978
inline Game GameNodeRep::GetGame() const { return m_game->shared_from_this(); }

src/games/gameagg.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ template <class T>
136136
T AGGMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, const GameStrategy &ps1,
137137
const GameStrategy &ps2) const
138138
{
139-
GamePlayerRep *player1 = ps1->GetPlayer();
140-
GamePlayerRep *player2 = ps2->GetPlayer();
139+
const auto player1 = ps1->GetPlayer().get();
140+
const auto player2 = ps2->GetPlayer().get();
141141
if (player1 == player2) {
142142
return (T)0;
143143
}
@@ -179,7 +179,7 @@ template class AGGMixedStrategyProfileRep<Rational>;
179179
GameAGGRep::GameAGGRep(std::shared_ptr<agg::AGG> p_aggPtr) : aggPtr(p_aggPtr)
180180
{
181181
for (int pl = 1; pl <= aggPtr->getNumPlayers(); pl++) {
182-
m_players.push_back(new GamePlayerRep(this, pl, aggPtr->getNumActions(pl - 1)));
182+
m_players.push_back(std::make_shared<GamePlayerRep>(this, pl, aggPtr->getNumActions(pl - 1)));
183183
m_players.back()->m_label = lexical_cast<std::string>(pl);
184184
std::for_each(m_players.back()->m_strategies.begin(), m_players.back()->m_strategies.end(),
185185
[st = 1](GameStrategyRep *s) mutable { s->SetLabel(std::to_string(st++)); });

src/games/gamebagg.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ template <class T>
156156
T BAGGMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, const GameStrategy &ps1,
157157
const GameStrategy &ps2) const
158158
{
159-
GamePlayerRep *player1 = ps1->GetPlayer();
160-
GamePlayerRep *player2 = ps2->GetPlayer();
159+
const auto player1 = ps1->GetPlayer().get();
160+
const auto player2 = ps2->GetPlayer().get();
161161
if (player1 == player2) {
162162
return (T)0;
163163
}
@@ -212,7 +212,8 @@ GameBAGGRep::GameBAGGRep(std::shared_ptr<agg::BAGG> _baggPtr)
212212
int k = 1;
213213
for (int pl = 1; pl <= baggPtr->getNumPlayers(); pl++) {
214214
for (int j = 0; j < baggPtr->getNumTypes(pl - 1); j++, k++) {
215-
m_players.push_back(new GamePlayerRep(this, k, baggPtr->getNumActions(pl - 1, j)));
215+
m_players.push_back(
216+
std::make_shared<GamePlayerRep>(this, k, baggPtr->getNumActions(pl - 1, j)));
216217
m_players.back()->m_label = std::to_string(k);
217218
agent2baggPlayer[k] = pl;
218219
std::for_each(m_players.back()->m_strategies.begin(), m_players.back()->m_strategies.end(),

src/games/gameobject.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#ifndef GAMBIT_GAMES_GAMEOBJECT_H
2424
#define GAMBIT_GAMES_GAMEOBJECT_H
2525

26+
#include <memory>
27+
2628
namespace Gambit {
2729

2830
/// This is a base class for all game-related objects. Primary among
@@ -161,6 +163,53 @@ template <class T> class GameObjectPtr {
161163
bool operator!() const { return !rep; }
162164
};
163165

166+
template <class T> class GameObjectSmartPtr {
167+
private:
168+
std::shared_ptr<T> m_rep;
169+
170+
public:
171+
GameObjectSmartPtr() = default;
172+
GameObjectSmartPtr(std::nullptr_t r) : m_rep(r) {}
173+
GameObjectSmartPtr(std::shared_ptr<T> r) : m_rep(r) {}
174+
GameObjectSmartPtr(const GameObjectSmartPtr<T> &) = default;
175+
~GameObjectSmartPtr() = default;
176+
177+
GameObjectSmartPtr<T> &operator=(const GameObjectSmartPtr<T> &) = default;
178+
179+
std::shared_ptr<T> operator->() const
180+
{
181+
if (!m_rep) {
182+
throw NullException();
183+
}
184+
if (!m_rep->IsValid()) {
185+
throw InvalidObjectException();
186+
}
187+
return m_rep;
188+
}
189+
T *get() const
190+
{
191+
if (!m_rep) {
192+
throw NullException();
193+
}
194+
if (!m_rep->IsValid()) {
195+
throw InvalidObjectException();
196+
}
197+
return m_rep.get();
198+
}
199+
200+
bool operator==(const GameObjectSmartPtr<T> &r) const { return (m_rep == r.m_rep); }
201+
bool operator==(const std::shared_ptr<T> r) const { return (m_rep == r); }
202+
bool operator==(const std::shared_ptr<const T> r) const { return (m_rep == r); }
203+
bool operator==(const std::nullptr_t) const { return !bool(m_rep); }
204+
bool operator!=(const GameObjectSmartPtr<T> &r) const { return (m_rep != r.m_rep); }
205+
bool operator!=(const std::shared_ptr<T> r) const { return (m_rep != r); }
206+
bool operator!=(const std::shared_ptr<const T> r) const { return (m_rep != r); }
207+
bool operator!=(const std::nullptr_t) const { return bool(m_rep); }
208+
bool operator<(const GameObjectSmartPtr<T> &r) const { return (m_rep < r.m_rep); }
209+
210+
operator bool() const noexcept { return bool(m_rep); }
211+
operator std::shared_ptr<T>() const { return m_rep; }
212+
};
164213
} // end namespace Gambit
165214

166215
#endif // GAMBIT_GAMES_GAMEOBJECT_H

0 commit comments

Comments
 (0)