Skip to content

Commit

Permalink
(WIP) removing Set and Dictionary, to be replaced with STL
Browse files Browse the repository at this point in the history
  • Loading branch information
heyx3 committed Dec 24, 2024
1 parent 310b734 commit 4a75368
Show file tree
Hide file tree
Showing 27 changed files with 376 additions and 228 deletions.
1 change: 0 additions & 1 deletion WFC++.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ xcopy "$(ProjectDir)WFC++\*.hpp" "$(TargetDir)include" /sy</Command>
<ClInclude Include="WFC++\Dictionary.hpp" />
<ClInclude Include="WFC++\EnumFlags.h" />
<ClInclude Include="WFC++\HelperClasses.h" />
<ClInclude Include="WFC++\List.hpp" />
<ClInclude Include="WFC++\MemoryChecks.inl" />
<ClInclude Include="WFC++\Tiled3D\StandardRunner.h" />
<ClInclude Include="WFC++\WFCppStreamPrinting.hpp" />
Expand Down
3 changes: 0 additions & 3 deletions WFC++.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@
<ClInclude Include="WFC++\Dictionary.hpp">
<Filter>Helper Classes</Filter>
</ClInclude>
<ClInclude Include="WFC++\List.hpp">
<Filter>Helper Classes</Filter>
</ClInclude>
<ClInclude Include="WFC++\HelperClasses.h" />
<ClInclude Include="WFC++\Platform.h" />
<ClInclude Include="WFC++\Simple\InputData.h">
Expand Down
16 changes: 8 additions & 8 deletions WFC++/Dictionary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace WFC
{
template<typename TKey, typename TValue, typename Hasher = TKey>
template<typename TKey, typename TValue>
//A wrapper around std::unordered_map so that it can cross DLL boundaries.
class Dictionary
{
Expand All @@ -33,7 +33,7 @@ namespace WFC
}
TValue* TryGet(const TKey& key)
{
return (TValue*)((const Dictionary<TKey, TValue, Hasher>*)this)->TryGet(key);
return (TValue*)((const Dictionary<TKey, TValue>*)this)->TryGet(key);
}

const TValue& Get(const TKey& key, const TValue& valIfNotFound) const
Expand All @@ -45,7 +45,7 @@ namespace WFC
}
TValue& Get(const TKey& key, const TValue& valIfNotFound)
{
return (TValue&)((const Dictionary<TKey, TValue, Hasher>*)this)->Get(key, valIfNotFound);
return (TValue&)((const Dictionary<TKey, TValue>*)this)->Get(key, valIfNotFound);
}

template<typename NumberType>
Expand All @@ -63,13 +63,13 @@ namespace WFC

//Iterators for ranged-for loops.
//We can't use "auto" for the return type here because it breaks SWIG.
typename std::unordered_map<TKey, TValue, Hasher>::const_iterator begin() const { return dict.begin(); }
typename std::unordered_map<TKey, TValue, Hasher>::iterator begin() { return dict.begin(); }
typename std::unordered_map<TKey, TValue, Hasher>::const_iterator end() const { return dict.end(); }
typename std::unordered_map<TKey, TValue, Hasher>::iterator end() { return dict.end(); }
typename std::unordered_map<TKey, TValue>::const_iterator begin() const { return dict.begin(); }
typename std::unordered_map<TKey, TValue>::iterator begin() { return dict.begin(); }
typename std::unordered_map<TKey, TValue>::const_iterator end() const { return dict.end(); }
typename std::unordered_map<TKey, TValue>::iterator end() { return dict.end(); }

private:

std::unordered_map<TKey, TValue, Hasher> dict;
std::unordered_map<TKey, TValue> dict;
};
}
12 changes: 6 additions & 6 deletions WFC++/HelperClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
#include "Array2D.hpp"
#include "Array3D.hpp"
#include "Array4D.hpp"
#include "Set.hpp"
#include "Dictionary.hpp"
#include <unordered_set>
#include <unordered_map>
#include "EnumFlags.h"
#include "xoshiro.hpp"

Expand All @@ -27,9 +27,9 @@ namespace WFC
//Returns a random index from the 'weights' list, using its elements as random weights.
//Returns -1 if there are no elements or your weights don't sum to a positive number.
template<typename Weight, typename Rng, typename WeightsAllocator>
int PickWeightedRandomIndex(Rng& rng,
std::vector<Weight, WeightsAllocator>& weights,
Weight cachedTotalWeight = -1)
ptrdiff_t PickWeightedRandomIndex(Rng& rng,
std::vector<Weight, WeightsAllocator>& weights,
Weight cachedTotalWeight = -1)
{
if (weights.size() < 1)
return -1;
Expand Down Expand Up @@ -61,6 +61,6 @@ namespace WFC
if (remainingBudget <= 0)
return i;
}
return static_cast<size_t>(weights.size() - 1);
return static_cast<ptrdiff_t>(weights.size()) - 1;
}
}
2 changes: 1 addition & 1 deletion WFC++/Simple/InputData.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace WFC
{
namespace Simple
{
using PixelFrequencyLookup = Dictionary<Pixel, size_t, std::hash<Pixel>>;
using PixelFrequencyLookup = std::unordered_map<Pixel, size_t>;

//TODO: Support diagonal reflections.

Expand Down
13 changes: 9 additions & 4 deletions WFC++/Simple/Pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ namespace WFC

//Gets the hash value for the given instance.
size_t GetHashcode() const;
//Gets the hash value for the given instance.
//Enables this class to be used as a key in Dictionary<> or std::unordered_map<>.
size_t operator()(const Pattern& v) const { return v.GetHashcode(); }

//Gets whether this pattern is functionally identical to the given one.
bool HasSameData(const Pattern& p) const;
Expand All @@ -60,4 +57,12 @@ namespace WFC
bool DoesFit(Vector2i outputMinCorner, const State& outputState) const;
};
}
}
}

template<> struct std::hash<WFC::Simple::Pattern>
{
size_t operator()(const WFC::Simple::Pattern& p) const
{
return p.GetHashcode();
}
};
21 changes: 12 additions & 9 deletions WFC++/Simple/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ std::optional<bool> State::Iterate(Vector2i& out_changedPos, std::vector<Vector2
return true;

//If any pixels are impossible to solve, handle it.
size_t nColorChoices = Output[lowestEntropyPixelPoses[0]].ColorFrequencies.GetSize();
size_t nColorChoices = Output[lowestEntropyPixelPoses[0]].ColorFrequencies.size();
if (nColorChoices == 0)
{
//Either clear out the violating pixels, or give up.
if (ViolationClearSize > 0)
{
//Clear all violating pixels, and collect all positions that will be affected by this.
std::unordered_set<Vector2i, Vector2i> affectedPoses;
std::unordered_set<Vector2i> affectedPoses;
for (size_t i = 0; i < lowestEntropyPixelPoses.size(); ++i)
for (Vector2i affectedPos : ClearArea(lowestEntropyPixelPoses[i]))
affectedPoses.emplace(affectedPos);
affectedPoses.insert(affectedPos);

//Recalculate positions that will be affected by this.
for (Vector2i affectedPos : affectedPoses)
Expand All @@ -68,7 +68,7 @@ std::optional<bool> State::Iterate(Vector2i& out_changedPos, std::vector<Vector2
//Pick a color at random for the pixel to have.
Pixel chosenColor = -1; //Dummy value to keep the compiler hapy
//If there's only one possible color, this is easy.
if (chosenPixel.ColorFrequencies.GetSize() == 1)
if (chosenPixel.ColorFrequencies.size() == 1)
{
for (const auto& kvp : chosenPixel.ColorFrequencies)
chosenColor = kvp.first;
Expand All @@ -77,8 +77,8 @@ std::optional<bool> State::Iterate(Vector2i& out_changedPos, std::vector<Vector2
else
{
//Get a list of values and corresponding weights.
std::vector<Pixel> colors(chosenPixel.ColorFrequencies.GetSize());
std::vector<double> weights(chosenPixel.ColorFrequencies.GetSize());
std::vector<Pixel> colors(chosenPixel.ColorFrequencies.size());
std::vector<double> weights(chosenPixel.ColorFrequencies.size());
size_t index = 0;
for (const auto& colAndWeight : chosenPixel.ColorFrequencies)
{
Expand Down Expand Up @@ -142,8 +142,11 @@ void State::GetBestPixels(std::vector<Vector2i>& outValues) const
auto& pixel = Output[outputPos];
if (!pixel.Value.has_value())
{
size_t pixelEntropy = pixel.ColorFrequencies.Sum<size_t>(
[](const size_t& weight) { return weight; });
size_t pixelEntropy = std::accumulate(
pixel.ColorFrequencies.begin(), pixel.ColorFrequencies.end(),
size_t{ 0 },
[&](size_t sum, const auto& entry) { return sum + entry.second; }
);

//If it's less than the current minimum, we've found a new minimum.
if (pixelEntropy < minEntropy)
Expand Down Expand Up @@ -212,7 +215,7 @@ void State::RecalculatePixelChances(Vector2i pixelPos)
}

//Check which patterns can be applied at which positions around this pixel.
pixel.ColorFrequencies.Clear();
pixel.ColorFrequencies.clear();
for (size_t patternI = 0; patternI < Input.GetPatterns().size(); ++patternI)
{
//Try placing this pattern everywhere that touches the pixel.
Expand Down
2 changes: 1 addition & 1 deletion WFC++/Tiled/InputData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ InputData::InputData(const std::vector<Tile>& _tiles)
for (uint8_t edgeI = 0; edgeI < 4; ++edgeI)
{
auto key = EdgeInstance(tile.Edges[edgeI], (EdgeDirs)edgeI);
matchingEdges[key].Add(tileID);
matchingEdges[key].insert(tileID);
}
}
}
68 changes: 38 additions & 30 deletions WFC++/Tiled/InputData.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,50 @@
#include "Tile.hpp"


//The helper struct and its std::hash must be defined first.
namespace WFC
{
namespace Tiled
{
//A specific edge type and direction.
struct EdgeInstance
{
EdgeID Type;
EdgeDirs Dir;

EdgeInstance() : Type(0), Dir((EdgeDirs)0) {}
EdgeInstance(EdgeID type, EdgeDirs connectionDir)
: Type(type), Dir(connectionDir) {
}

inline bool operator==(const EdgeInstance& t2) const
{
return (Type == t2.Type) & (Dir == t2.Dir);
}
inline bool operator!=(const EdgeInstance& t2) const { return !(operator==(t2)); }
};
}
}
template<> struct std::hash<WFC::Tiled::EdgeInstance>
{
size_t operator()(const WFC::Tiled::EdgeInstance& d) const {
return WFC::Vector2i(d.Type, d.Dir).GetHashcodeLarge();
}
};

namespace WFC
{
namespace Tiled
{
//A collection of tiles, by their ID.
using TileIDSet = Set<TileID, std::hash<TileID>>;
using TileIDSet = std::unordered_set<TileID>;


//Tile data for the WFC algorithm to generate from.
//Pre-computes and caches important queries for the algorithm.
class WFC_API InputData
{
public:
//A specific edge type and direction.
struct EdgeInstance
{
EdgeID Type;
EdgeDirs Dir;

EdgeInstance() : Type(0), Dir((EdgeDirs)0) { }
EdgeInstance(EdgeID type, EdgeDirs connectionDir)
: Type(type), Dir(connectionDir) { }

//Gets the hash value for an instance.
//Allows it to be used as a Dictionary<> key.
inline unsigned int operator()(const EdgeInstance& t) const
{
//Use the Vector2i hasher that already exists.
Vector2i v2(t.Type, t.Dir);
return Vector2i()(v2);
}

inline bool operator==(const EdgeInstance& t2) const
{
return (Type == t2.Type) & (Dir == t2.Dir);
}
inline bool operator!=(const EdgeInstance& t2) const { return !(operator==(t2)); }
};


InputData(const std::vector<Tile>& tiles);
InputData() : InputData(std::vector<Tile>()) { }
Expand All @@ -53,8 +58,11 @@ namespace WFC
//Gets all tiles that have the given edge type on the given side.
inline const TileIDSet& GetTilesWithEdge(EdgeID type, EdgeDirs side) const
{
return matchingEdges.Get(EdgeInstance(type, side),
EmptyTileSet);
auto found = matchingEdges.find({ type, side });
if (found == matchingEdges.end())
return EmptyTileSet;
else
return found->second;
}

private:
Expand All @@ -63,7 +71,7 @@ namespace WFC
std::vector<Tile> tiles;

//A quick lookup of which tiles have a certain edge type in a certain direction.
Dictionary<EdgeInstance, TileIDSet> matchingEdges;
std::unordered_map<EdgeInstance, TileIDSet> matchingEdges;


//The default response for "GetTilesWithEdge()".
Expand Down
Loading

0 comments on commit 4a75368

Please sign in to comment.