1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-23 14:54:30 +01:00

Merge pull request #15058 from ZehMatt/enummap

Refactor lookup tables to use EnumMap
This commit is contained in:
Michael Steenbeek
2021-07-29 16:51:10 +02:00
committed by GitHub
13 changed files with 566 additions and 272 deletions

View File

@@ -767,6 +767,7 @@
F42186C5840D4196981ADD16 /* EntityTweener.h in Headers */ = {isa = PBXBuildFile; fileRef = 091352A950004312BAB18717 /* EntityTweener.h */; };
0746674FA0794ABF86E406A1 /* Litter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9D3DD6CD73F5421880280D9D /* Litter.cpp */; };
B9B6F97CE24E4A559C7BBA0A /* RideConstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6BCCA2EF0F5A40D5B83A83AC /* RideConstruction.cpp */; };
317B766A750D4365B22A1682 /* EnumMap.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BA2317BF6FB54E328DEB7055 /* EnumMap.hpp */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -1836,6 +1837,7 @@
091352A950004312BAB18717 /* EntityTweener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = EntityTweener.h; path = src/openrct2/world/EntityTweener.h; sourceTree = SOURCE_ROOT; };
9D3DD6CD73F5421880280D9D /* Litter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Litter.cpp; path = src/openrct2/world/Litter.cpp; sourceTree = SOURCE_ROOT; };
6BCCA2EF0F5A40D5B83A83AC /* RideConstruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RideConstruction.cpp; path = src/openrct2/ride/RideConstruction.cpp; sourceTree = SOURCE_ROOT; };
BA2317BF6FB54E328DEB7055 /* EnumMap.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = EnumMap.hpp; path = src/openrct2/core/EnumMap.hpp; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -2503,6 +2505,7 @@
4C8BB67F25533D64005C8830 /* StringReader.h */,
F76C83991EC4E7CC00FA49E2 /* Zip.cpp */,
F76C839A1EC4E7CC00FA49E2 /* Zip.h */,
BA2317BF6FB54E328DEB7055 /* EnumMap.hpp */,
);
path = core;
sourceTree = "<group>";
@@ -3468,6 +3471,7 @@
2ADE2F342244191E002598AF /* VirtualFloor.h in Headers */,
66A10F8B257F1E1800DD651A /* LandSmoothAction.h in Headers */,
F42186C5840D4196981ADD16 /* EntityTweener.h in Headers */,
317B766A750D4365B22A1682 /* EnumMap.hpp in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -0,0 +1,157 @@
/*****************************************************************************
* Copyright (c) 2014-2021 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#include <algorithm>
#include <array>
#include <string_view>
#include <vector>
/**
* Bi-directional map for converting between strings and enums / numbers.
*/
template<typename T> class EnumMap
{
private:
std::vector<std::pair<std::string_view, T>> _map;
bool _continiousValueIndex{ false };
static constexpr size_t BucketSize = 43;
std::array<std::vector<int32_t>, BucketSize> _buckets;
static constexpr bool ValueIndexable()
{
if constexpr (std::is_enum_v<T>)
return true;
else if constexpr (std::is_integral_v<T>)
return true;
return false;
}
static constexpr auto ValueDistance(T a, T b)
{
if constexpr (std::is_enum_v<T>)
return static_cast<std::underlying_type_t<T>>(b) - static_cast<std::underlying_type_t<T>>(a);
else if constexpr (std::is_integral_v<T>)
return (b - a);
}
static constexpr uint32_t MakeHash(const std::string_view str)
{
uint32_t res = 0x811c9dc5;
for (auto chr : str)
{
res ^= chr;
res *= 0x01000193;
}
return res;
}
public:
EnumMap(const std::initializer_list<std::pair<std::string_view, T>>&& items)
: _map{ items }
{
std::sort(_map.begin(), _map.end(), [](const auto& a, const auto& b) { return a.second < b.second; });
if constexpr (ValueIndexable())
{
_continiousValueIndex = true;
T cur{};
for (size_t i = 1; i < _map.size(); i++)
{
auto nextVal = _map[i].second;
auto dist = ValueDistance(cur, _map[i].second);
if (dist != 1)
{
_continiousValueIndex = false;
break;
}
cur = nextVal;
}
}
int32_t index = 0;
for (auto& kv : _map)
{
auto hash = MakeHash(kv.first);
auto bucketIndex = hash % BucketSize;
auto& bucket = _buckets[bucketIndex];
bucket.push_back(index);
index++;
}
}
std::string_view operator[](T k) const
{
auto it = find(k);
return it->first;
}
T operator[](std::string_view k) const
{
auto it = find(k);
return it->second;
}
auto find(const std::string_view k) const
{
const auto hash = MakeHash(k);
const auto bucketIndex = hash % BucketSize;
const auto& bucket = _buckets[bucketIndex];
for (auto index : bucket)
{
auto& entry = _map[index];
if (entry.first == k)
{
return _map.begin() + index;
}
}
return end();
}
auto find(const T k) const
{
const auto binarySearchValue = [&]() {
auto it = std::lower_bound(_map.begin(), _map.end(), k, [](const auto& a, const auto& b) { return a.second < b; });
if (it == _map.end() || it->second != k)
return end();
return it;
};
if constexpr (ValueIndexable())
{
if (_continiousValueIndex)
{
auto index = static_cast<size_t>(k);
return _map.begin() + index;
}
else
{
return binarySearchValue();
}
}
else
{
return binarySearchValue();
}
}
auto begin() const
{
return _map.begin();
}
auto end() const
{
return _map.end();
}
};

View File

@@ -9,12 +9,12 @@
#include "Colour.h"
#include "../core/EnumMap.hpp"
#include "../drawing/Drawing.h"
#include "../sprites.h"
#include <algorithm>
#include <cmath>
#include <unordered_map>
rct_colour_map ColourMapA[COLOUR_COUNT] = {};
@@ -60,45 +60,47 @@ void colours_init_maps()
namespace Colour
{
static const EnumMap<colour_t> LookupTable{
{ "black", COLOUR_BLACK },
{ "grey", COLOUR_GREY },
{ "white", COLOUR_WHITE },
{ "dark_purple", COLOUR_DARK_PURPLE },
{ "light_purple", COLOUR_LIGHT_PURPLE },
{ "bright_purple", COLOUR_BRIGHT_PURPLE },
{ "dark_blue", COLOUR_DARK_BLUE },
{ "light_blue", COLOUR_LIGHT_BLUE },
{ "icy_blue", COLOUR_ICY_BLUE },
{ "teal", COLOUR_TEAL },
{ "aquamarine", COLOUR_AQUAMARINE },
{ "saturated_green", COLOUR_SATURATED_GREEN },
{ "dark_green", COLOUR_DARK_GREEN },
{ "moss_green", COLOUR_MOSS_GREEN },
{ "bright_green", COLOUR_BRIGHT_GREEN },
{ "olive_green", COLOUR_OLIVE_GREEN },
{ "dark_olive_green", COLOUR_DARK_OLIVE_GREEN },
{ "bright_yellow", COLOUR_BRIGHT_YELLOW },
{ "yellow", COLOUR_YELLOW },
{ "dark_yellow", COLOUR_DARK_YELLOW },
{ "light_orange", COLOUR_LIGHT_ORANGE },
{ "dark_orange", COLOUR_DARK_ORANGE },
{ "light_brown", COLOUR_LIGHT_BROWN },
{ "saturated_brown", COLOUR_SATURATED_BROWN },
{ "dark_brown", COLOUR_DARK_BROWN },
{ "salmon_pink", COLOUR_SALMON_PINK },
{ "bordeaux_red", COLOUR_BORDEAUX_RED },
{ "saturated_red", COLOUR_SATURATED_RED },
{ "bright_red", COLOUR_BRIGHT_RED },
{ "dark_pink", COLOUR_DARK_PINK },
{ "bright_pink", COLOUR_BRIGHT_PINK },
{ "light_pink", COLOUR_LIGHT_PINK },
};
colour_t FromString(std::string_view s, colour_t defaultValue)
{
static const std::unordered_map<std::string_view, colour_t> LookupTable{
{ "black", COLOUR_BLACK },
{ "grey", COLOUR_GREY },
{ "white", COLOUR_WHITE },
{ "dark_purple", COLOUR_DARK_PURPLE },
{ "light_purple", COLOUR_LIGHT_PURPLE },
{ "bright_purple", COLOUR_BRIGHT_PURPLE },
{ "dark_blue", COLOUR_DARK_BLUE },
{ "light_blue", COLOUR_LIGHT_BLUE },
{ "icy_blue", COLOUR_ICY_BLUE },
{ "teal", COLOUR_TEAL },
{ "aquamarine", COLOUR_AQUAMARINE },
{ "saturated_green", COLOUR_SATURATED_GREEN },
{ "dark_green", COLOUR_DARK_GREEN },
{ "moss_green", COLOUR_MOSS_GREEN },
{ "bright_green", COLOUR_BRIGHT_GREEN },
{ "olive_green", COLOUR_OLIVE_GREEN },
{ "dark_olive_green", COLOUR_DARK_OLIVE_GREEN },
{ "bright_yellow", COLOUR_BRIGHT_YELLOW },
{ "yellow", COLOUR_YELLOW },
{ "dark_yellow", COLOUR_DARK_YELLOW },
{ "light_orange", COLOUR_LIGHT_ORANGE },
{ "dark_orange", COLOUR_DARK_ORANGE },
{ "light_brown", COLOUR_LIGHT_BROWN },
{ "saturated_brown", COLOUR_SATURATED_BROWN },
{ "dark_brown", COLOUR_DARK_BROWN },
{ "salmon_pink", COLOUR_SALMON_PINK },
{ "bordeaux_red", COLOUR_BORDEAUX_RED },
{ "saturated_red", COLOUR_SATURATED_RED },
{ "bright_red", COLOUR_BRIGHT_RED },
{ "dark_pink", COLOUR_DARK_PINK },
{ "bright_pink", COLOUR_BRIGHT_PINK },
{ "light_pink", COLOUR_LIGHT_PINK },
};
auto result = LookupTable.find(s);
return (result != LookupTable.end()) ? result->second : defaultValue;
}
} // namespace Colour
#ifndef NO_TTF

View File

@@ -9,43 +9,45 @@
#include "Cursors.h"
#include "../core/EnumMap.hpp"
#include <string>
#include <unordered_map>
namespace Cursor
{
static const EnumMap<CursorID> LookupTable{
{ "CURSOR_BLANK", CursorID::Blank },
{ "CURSOR_UP_ARROW", CursorID::UpArrow },
{ "CURSOR_UP_DOWN_ARROW", CursorID::UpDownArrow },
{ "CURSOR_HAND_POINT", CursorID::HandPoint },
{ "CURSOR_ZZZ", CursorID::ZZZ },
{ "CURSOR_DIAGONAL_ARROWS", CursorID::DiagonalArrows },
{ "CURSOR_PICKER", CursorID::Picker },
{ "CURSOR_TREE_DOWN", CursorID::TreeDown },
{ "CURSOR_FOUNTAIN_DOWN", CursorID::FountainDown },
{ "CURSOR_STATUE_DOWN", CursorID::StatueDown },
{ "CURSOR_BENCH_DOWN", CursorID::BenchDown },
{ "CURSOR_CROSS_HAIR", CursorID::CrossHair },
{ "CURSOR_BIN_DOWN", CursorID::BinDown },
{ "CURSOR_LAMPPOST_DOWN", CursorID::LamppostDown },
{ "CURSOR_FENCE_DOWN", CursorID::FenceDown },
{ "CURSOR_FLOWER_DOWN", CursorID::FlowerDown },
{ "CURSOR_PATH_DOWN", CursorID::PathDown },
{ "CURSOR_DIG_DOWN", CursorID::DigDown },
{ "CURSOR_WATER_DOWN", CursorID::WaterDown },
{ "CURSOR_HOUSE_DOWN", CursorID::HouseDown },
{ "CURSOR_VOLCANO_DOWN", CursorID::VolcanoDown },
{ "CURSOR_WALK_DOWN", CursorID::WalkDown },
{ "CURSOR_PAINT_DOWN", CursorID::PaintDown },
{ "CURSOR_ENTRANCE_DOWN", CursorID::EntranceDown },
{ "CURSOR_HAND_OPEN", CursorID::HandOpen },
{ "CURSOR_HAND_CLOSED", CursorID::HandClosed },
{ "CURSOR_ARROW", CursorID::Arrow },
};
CursorID FromString(const std::string& s, CursorID defaultValue)
{
assert(defaultValue != CursorID::Undefined);
static const std::unordered_map<std::string, CursorID> LookupTable{
{ "CURSOR_BLANK", CursorID::Blank },
{ "CURSOR_UP_ARROW", CursorID::UpArrow },
{ "CURSOR_UP_DOWN_ARROW", CursorID::UpDownArrow },
{ "CURSOR_HAND_POINT", CursorID::HandPoint },
{ "CURSOR_ZZZ", CursorID::ZZZ },
{ "CURSOR_DIAGONAL_ARROWS", CursorID::DiagonalArrows },
{ "CURSOR_PICKER", CursorID::Picker },
{ "CURSOR_TREE_DOWN", CursorID::TreeDown },
{ "CURSOR_FOUNTAIN_DOWN", CursorID::FountainDown },
{ "CURSOR_STATUE_DOWN", CursorID::StatueDown },
{ "CURSOR_BENCH_DOWN", CursorID::BenchDown },
{ "CURSOR_CROSS_HAIR", CursorID::CrossHair },
{ "CURSOR_BIN_DOWN", CursorID::BinDown },
{ "CURSOR_LAMPPOST_DOWN", CursorID::LamppostDown },
{ "CURSOR_FENCE_DOWN", CursorID::FenceDown },
{ "CURSOR_FLOWER_DOWN", CursorID::FlowerDown },
{ "CURSOR_PATH_DOWN", CursorID::PathDown },
{ "CURSOR_DIG_DOWN", CursorID::DigDown },
{ "CURSOR_WATER_DOWN", CursorID::WaterDown },
{ "CURSOR_HOUSE_DOWN", CursorID::HouseDown },
{ "CURSOR_VOLCANO_DOWN", CursorID::VolcanoDown },
{ "CURSOR_WALK_DOWN", CursorID::WalkDown },
{ "CURSOR_PAINT_DOWN", CursorID::PaintDown },
{ "CURSOR_ENTRANCE_DOWN", CursorID::EntranceDown },
{ "CURSOR_HAND_OPEN", CursorID::HandOpen },
{ "CURSOR_HAND_CLOSED", CursorID::HandClosed },
{ "CURSOR_ARROW", CursorID::Arrow },
};
auto result = LookupTable.find(s);
return (result != LookupTable.end()) ? result->second : defaultValue;

View File

@@ -157,6 +157,7 @@
<ClInclude Include="core\DataSerialiserTraits.h" />
<ClInclude Include="core\Diagnostics.hpp" />
<ClInclude Include="core\Endianness.h" />
<ClInclude Include="core\EnumMap.hpp" />
<ClInclude Include="core\File.h" />
<ClInclude Include="core\FileIndex.hpp" />
<ClInclude Include="core\FileScanner.h" />

View File

@@ -9,13 +9,14 @@
#include "FormatCodes.h"
#include "../core/EnumMap.hpp"
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
// clang-format off
static const std::unordered_map<std::string_view, FormatToken> FormatTokenMap = {
static const EnumMap<FormatToken> FormatTokenMap = {
{ "MOVE_X", FormatToken::Move, },
{ "NEWLINE", FormatToken::Newline, },
{ "NEWLINE_SMALLER", FormatToken::NewlineSmall, },
@@ -97,13 +98,10 @@ std::string_view FormatTokenToString(FormatToken token, bool withBraces)
}
else
{
for (const auto& t : FormatTokenMap)
{
if (t.second == token)
{
return t.first;
}
}
auto it = FormatTokenMap.find(token);
if (it != FormatTokenMap.end())
return it->first;
return {};
}
}

View File

@@ -13,6 +13,7 @@
#include "../OpenRCT2.h"
#include "../audio/audio.h"
#include "../core/EnumMap.hpp"
#include "../core/IStream.hpp"
#include "../core/Json.hpp"
#include "../core/Memory.hpp"
@@ -969,155 +970,158 @@ bool RideObject::IsRideTypeShopOrFacility(uint8_t rideType)
}
}
static const EnumMap<uint8_t> RideTypeLookupTable{
{ "spiral_rc", RIDE_TYPE_SPIRAL_ROLLER_COASTER },
{ "stand_up_rc", RIDE_TYPE_STAND_UP_ROLLER_COASTER },
{ "suspended_swinging_rc", RIDE_TYPE_SUSPENDED_SWINGING_COASTER },
{ "inverted_rc", RIDE_TYPE_INVERTED_ROLLER_COASTER },
{ "junior_rc", RIDE_TYPE_JUNIOR_ROLLER_COASTER },
{ "miniature_railway", RIDE_TYPE_MINIATURE_RAILWAY },
{ "monorail", RIDE_TYPE_MONORAIL },
{ "mini_suspended_rc", RIDE_TYPE_MINI_SUSPENDED_COASTER },
{ "boat_hire", RIDE_TYPE_BOAT_HIRE },
{ "wooden_wild_mouse", RIDE_TYPE_WOODEN_WILD_MOUSE },
{ "steeplechase", RIDE_TYPE_STEEPLECHASE },
{ "car_ride", RIDE_TYPE_CAR_RIDE },
{ "launched_freefall", RIDE_TYPE_LAUNCHED_FREEFALL },
{ "bobsleigh_rc", RIDE_TYPE_BOBSLEIGH_COASTER },
{ "observation_tower", RIDE_TYPE_OBSERVATION_TOWER },
{ "looping_rc", RIDE_TYPE_LOOPING_ROLLER_COASTER },
{ "dinghy_slide", RIDE_TYPE_DINGHY_SLIDE },
{ "mine_train_rc", RIDE_TYPE_MINE_TRAIN_COASTER },
{ "chairlift", RIDE_TYPE_CHAIRLIFT },
{ "corkscrew_rc", RIDE_TYPE_CORKSCREW_ROLLER_COASTER },
{ "maze", RIDE_TYPE_MAZE },
{ "spiral_slide", RIDE_TYPE_SPIRAL_SLIDE },
{ "go_karts", RIDE_TYPE_GO_KARTS },
{ "log_flume", RIDE_TYPE_LOG_FLUME },
{ "river_rapids", RIDE_TYPE_RIVER_RAPIDS },
{ "dodgems", RIDE_TYPE_DODGEMS },
{ "swinging_ship", RIDE_TYPE_SWINGING_SHIP },
{ "swinging_inverter_ship", RIDE_TYPE_SWINGING_INVERTER_SHIP },
{ "food_stall", RIDE_TYPE_FOOD_STALL },
{ "drink_stall", RIDE_TYPE_DRINK_STALL },
{ "shop", RIDE_TYPE_SHOP },
{ "merry_go_round", RIDE_TYPE_MERRY_GO_ROUND },
{ "information_kiosk", RIDE_TYPE_INFORMATION_KIOSK },
{ "toilets", RIDE_TYPE_TOILETS },
{ "ferris_wheel", RIDE_TYPE_FERRIS_WHEEL },
{ "motion_simulator", RIDE_TYPE_MOTION_SIMULATOR },
{ "3d_cinema", RIDE_TYPE_3D_CINEMA },
{ "top_spin", RIDE_TYPE_TOP_SPIN },
{ "space_rings", RIDE_TYPE_SPACE_RINGS },
{ "reverse_freefall_rc", RIDE_TYPE_REVERSE_FREEFALL_COASTER },
{ "lift", RIDE_TYPE_LIFT },
{ "vertical_drop_rc", RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER },
{ "cash_machine", RIDE_TYPE_CASH_MACHINE },
{ "twist", RIDE_TYPE_TWIST },
{ "haunted_house", RIDE_TYPE_HAUNTED_HOUSE },
{ "first_aid", RIDE_TYPE_FIRST_AID },
{ "circus", RIDE_TYPE_CIRCUS },
{ "ghost_train", RIDE_TYPE_GHOST_TRAIN },
{ "twister_rc", RIDE_TYPE_TWISTER_ROLLER_COASTER },
{ "wooden_rc", RIDE_TYPE_WOODEN_ROLLER_COASTER },
{ "side_friction_rc", RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER },
{ "steel_wild_mouse", RIDE_TYPE_STEEL_WILD_MOUSE },
{ "multi_dimension_rc", RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER },
{ "flying_rc", RIDE_TYPE_FLYING_ROLLER_COASTER },
{ "virginia_reel", RIDE_TYPE_VIRGINIA_REEL },
{ "splash_boats", RIDE_TYPE_SPLASH_BOATS },
{ "mini_helicopters", RIDE_TYPE_MINI_HELICOPTERS },
{ "lay_down_rc", RIDE_TYPE_LAY_DOWN_ROLLER_COASTER },
{ "suspended_monorail", RIDE_TYPE_SUSPENDED_MONORAIL },
{ "reverser_rc", RIDE_TYPE_REVERSER_ROLLER_COASTER },
{ "heartline_twister_rc", RIDE_TYPE_HEARTLINE_TWISTER_COASTER },
{ "mini_golf", RIDE_TYPE_MINI_GOLF },
{ "giga_rc", RIDE_TYPE_GIGA_COASTER },
{ "roto_drop", RIDE_TYPE_ROTO_DROP },
{ "flying_saucers", RIDE_TYPE_FLYING_SAUCERS },
{ "crooked_house", RIDE_TYPE_CROOKED_HOUSE },
{ "monorail_cycles", RIDE_TYPE_MONORAIL_CYCLES },
{ "compact_inverted_rc", RIDE_TYPE_COMPACT_INVERTED_COASTER },
{ "water_coaster", RIDE_TYPE_WATER_COASTER },
{ "air_powered_vertical_rc", RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER },
{ "inverted_hairpin_rc", RIDE_TYPE_INVERTED_HAIRPIN_COASTER },
{ "magic_carpet", RIDE_TYPE_MAGIC_CARPET },
{ "submarine_ride", RIDE_TYPE_SUBMARINE_RIDE },
{ "river_rafts", RIDE_TYPE_RIVER_RAFTS },
{ "enterprise", RIDE_TYPE_ENTERPRISE },
{ "inverted_impulse_rc", RIDE_TYPE_INVERTED_IMPULSE_COASTER },
{ "mini_rc", RIDE_TYPE_MINI_ROLLER_COASTER },
{ "mine_ride", RIDE_TYPE_MINE_RIDE },
{ "lim_launched_rc", RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER },
{ "hypercoaster", RIDE_TYPE_HYPERCOASTER },
{ "hyper_twister", RIDE_TYPE_HYPER_TWISTER },
{ "monster_trucks", RIDE_TYPE_MONSTER_TRUCKS },
{ "spinning_wild_mouse", RIDE_TYPE_SPINNING_WILD_MOUSE },
{ "classic_mini_rc", RIDE_TYPE_CLASSIC_MINI_ROLLER_COASTER },
{ "hybrid_rc", RIDE_TYPE_HYBRID_COASTER },
{ "single_rail_rc", RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER },
};
uint8_t RideObject::ParseRideType(const std::string& s)
{
static const std::unordered_map<std::string, uint8_t> LookupTable{
{ "spiral_rc", RIDE_TYPE_SPIRAL_ROLLER_COASTER },
{ "stand_up_rc", RIDE_TYPE_STAND_UP_ROLLER_COASTER },
{ "suspended_swinging_rc", RIDE_TYPE_SUSPENDED_SWINGING_COASTER },
{ "inverted_rc", RIDE_TYPE_INVERTED_ROLLER_COASTER },
{ "junior_rc", RIDE_TYPE_JUNIOR_ROLLER_COASTER },
{ "miniature_railway", RIDE_TYPE_MINIATURE_RAILWAY },
{ "monorail", RIDE_TYPE_MONORAIL },
{ "mini_suspended_rc", RIDE_TYPE_MINI_SUSPENDED_COASTER },
{ "boat_hire", RIDE_TYPE_BOAT_HIRE },
{ "wooden_wild_mouse", RIDE_TYPE_WOODEN_WILD_MOUSE },
{ "steeplechase", RIDE_TYPE_STEEPLECHASE },
{ "car_ride", RIDE_TYPE_CAR_RIDE },
{ "launched_freefall", RIDE_TYPE_LAUNCHED_FREEFALL },
{ "bobsleigh_rc", RIDE_TYPE_BOBSLEIGH_COASTER },
{ "observation_tower", RIDE_TYPE_OBSERVATION_TOWER },
{ "looping_rc", RIDE_TYPE_LOOPING_ROLLER_COASTER },
{ "dinghy_slide", RIDE_TYPE_DINGHY_SLIDE },
{ "mine_train_rc", RIDE_TYPE_MINE_TRAIN_COASTER },
{ "chairlift", RIDE_TYPE_CHAIRLIFT },
{ "corkscrew_rc", RIDE_TYPE_CORKSCREW_ROLLER_COASTER },
{ "maze", RIDE_TYPE_MAZE },
{ "spiral_slide", RIDE_TYPE_SPIRAL_SLIDE },
{ "go_karts", RIDE_TYPE_GO_KARTS },
{ "log_flume", RIDE_TYPE_LOG_FLUME },
{ "river_rapids", RIDE_TYPE_RIVER_RAPIDS },
{ "dodgems", RIDE_TYPE_DODGEMS },
{ "swinging_ship", RIDE_TYPE_SWINGING_SHIP },
{ "swinging_inverter_ship", RIDE_TYPE_SWINGING_INVERTER_SHIP },
{ "food_stall", RIDE_TYPE_FOOD_STALL },
{ "drink_stall", RIDE_TYPE_DRINK_STALL },
{ "shop", RIDE_TYPE_SHOP },
{ "merry_go_round", RIDE_TYPE_MERRY_GO_ROUND },
{ "information_kiosk", RIDE_TYPE_INFORMATION_KIOSK },
{ "toilets", RIDE_TYPE_TOILETS },
{ "ferris_wheel", RIDE_TYPE_FERRIS_WHEEL },
{ "motion_simulator", RIDE_TYPE_MOTION_SIMULATOR },
{ "3d_cinema", RIDE_TYPE_3D_CINEMA },
{ "top_spin", RIDE_TYPE_TOP_SPIN },
{ "space_rings", RIDE_TYPE_SPACE_RINGS },
{ "reverse_freefall_rc", RIDE_TYPE_REVERSE_FREEFALL_COASTER },
{ "lift", RIDE_TYPE_LIFT },
{ "vertical_drop_rc", RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER },
{ "cash_machine", RIDE_TYPE_CASH_MACHINE },
{ "twist", RIDE_TYPE_TWIST },
{ "haunted_house", RIDE_TYPE_HAUNTED_HOUSE },
{ "first_aid", RIDE_TYPE_FIRST_AID },
{ "circus", RIDE_TYPE_CIRCUS },
{ "ghost_train", RIDE_TYPE_GHOST_TRAIN },
{ "twister_rc", RIDE_TYPE_TWISTER_ROLLER_COASTER },
{ "wooden_rc", RIDE_TYPE_WOODEN_ROLLER_COASTER },
{ "side_friction_rc", RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER },
{ "steel_wild_mouse", RIDE_TYPE_STEEL_WILD_MOUSE },
{ "multi_dimension_rc", RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER },
{ "flying_rc", RIDE_TYPE_FLYING_ROLLER_COASTER },
{ "virginia_reel", RIDE_TYPE_VIRGINIA_REEL },
{ "splash_boats", RIDE_TYPE_SPLASH_BOATS },
{ "mini_helicopters", RIDE_TYPE_MINI_HELICOPTERS },
{ "lay_down_rc", RIDE_TYPE_LAY_DOWN_ROLLER_COASTER },
{ "suspended_monorail", RIDE_TYPE_SUSPENDED_MONORAIL },
{ "reverser_rc", RIDE_TYPE_REVERSER_ROLLER_COASTER },
{ "heartline_twister_rc", RIDE_TYPE_HEARTLINE_TWISTER_COASTER },
{ "mini_golf", RIDE_TYPE_MINI_GOLF },
{ "giga_rc", RIDE_TYPE_GIGA_COASTER },
{ "roto_drop", RIDE_TYPE_ROTO_DROP },
{ "flying_saucers", RIDE_TYPE_FLYING_SAUCERS },
{ "crooked_house", RIDE_TYPE_CROOKED_HOUSE },
{ "monorail_cycles", RIDE_TYPE_MONORAIL_CYCLES },
{ "compact_inverted_rc", RIDE_TYPE_COMPACT_INVERTED_COASTER },
{ "water_coaster", RIDE_TYPE_WATER_COASTER },
{ "air_powered_vertical_rc", RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER },
{ "inverted_hairpin_rc", RIDE_TYPE_INVERTED_HAIRPIN_COASTER },
{ "magic_carpet", RIDE_TYPE_MAGIC_CARPET },
{ "submarine_ride", RIDE_TYPE_SUBMARINE_RIDE },
{ "river_rafts", RIDE_TYPE_RIVER_RAFTS },
{ "enterprise", RIDE_TYPE_ENTERPRISE },
{ "inverted_impulse_rc", RIDE_TYPE_INVERTED_IMPULSE_COASTER },
{ "mini_rc", RIDE_TYPE_MINI_ROLLER_COASTER },
{ "mine_ride", RIDE_TYPE_MINE_RIDE },
{ "lim_launched_rc", RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER },
{ "hypercoaster", RIDE_TYPE_HYPERCOASTER },
{ "hyper_twister", RIDE_TYPE_HYPER_TWISTER },
{ "monster_trucks", RIDE_TYPE_MONSTER_TRUCKS },
{ "spinning_wild_mouse", RIDE_TYPE_SPINNING_WILD_MOUSE },
{ "classic_mini_rc", RIDE_TYPE_CLASSIC_MINI_ROLLER_COASTER },
{ "hybrid_rc", RIDE_TYPE_HYBRID_COASTER },
{ "single_rail_rc", RIDE_TYPE_SINGLE_RAIL_ROLLER_COASTER }
};
auto result = LookupTable.find(s);
return (result != LookupTable.end()) ? result->second : static_cast<uint8_t>(RIDE_TYPE_NULL);
auto result = RideTypeLookupTable.find(s);
return (result != RideTypeLookupTable.end()) ? result->second : static_cast<uint8_t>(RIDE_TYPE_NULL);
}
static const EnumMap<uint8_t> RideCategoryLookupTable{
{ "transport", RIDE_CATEGORY_TRANSPORT },
{ "gentle", RIDE_CATEGORY_GENTLE },
{ "rollercoaster", RIDE_CATEGORY_ROLLERCOASTER },
{ "thrill", RIDE_CATEGORY_THRILL },
{ "water", RIDE_CATEGORY_WATER },
{ "stall", RIDE_CATEGORY_SHOP },
};
uint8_t RideObject::ParseRideCategory(const std::string& s)
{
static const std::unordered_map<std::string, uint8_t> LookupTable{
{ "transport", RIDE_CATEGORY_TRANSPORT },
{ "gentle", RIDE_CATEGORY_GENTLE },
{ "rollercoaster", RIDE_CATEGORY_ROLLERCOASTER },
{ "thrill", RIDE_CATEGORY_THRILL },
{ "water", RIDE_CATEGORY_WATER },
{ "stall", RIDE_CATEGORY_SHOP },
};
auto result = LookupTable.find(s);
return (result != LookupTable.end()) ? result->second : static_cast<uint8_t>(RIDE_CATEGORY_TRANSPORT);
auto result = RideCategoryLookupTable.find(s);
return (result != RideCategoryLookupTable.end()) ? result->second : static_cast<uint8_t>(RIDE_CATEGORY_TRANSPORT);
}
static const EnumMap<ShopItem> ShopItemLookupTable{
{ "burger", ShopItem::Burger },
{ "chips", ShopItem::Chips },
{ "ice_cream", ShopItem::IceCream },
{ "candyfloss", ShopItem::Candyfloss },
{ "pizza", ShopItem::Pizza },
{ "popcorn", ShopItem::Popcorn },
{ "hot_dog", ShopItem::HotDog },
{ "tentacle", ShopItem::Tentacle },
{ "toffee_apple", ShopItem::ToffeeApple },
{ "doughnut", ShopItem::Doughnut },
{ "chicken", ShopItem::Chicken },
{ "pretzel", ShopItem::Pretzel },
{ "funnel_cake", ShopItem::FunnelCake },
{ "beef_noodles", ShopItem::BeefNoodles },
{ "fried_rice_noodles", ShopItem::FriedRiceNoodles },
{ "wonton_soup", ShopItem::WontonSoup },
{ "meatball_soup", ShopItem::MeatballSoup },
{ "sub_sandwich", ShopItem::SubSandwich },
{ "cookie", ShopItem::Cookie },
{ "roast_sausage", ShopItem::RoastSausage },
{ "drink", ShopItem::Drink },
{ "coffee", ShopItem::Coffee },
{ "lemonade", ShopItem::Lemonade },
{ "chocolate", ShopItem::Chocolate },
{ "iced_tea", ShopItem::IcedTea },
{ "fruit_juice", ShopItem::FruitJuice },
{ "soybean_milk", ShopItem::SoybeanMilk },
{ "sujeonggwa", ShopItem::Sujeonggwa },
{ "balloon", ShopItem::Balloon },
{ "toy", ShopItem::Toy },
{ "map", ShopItem::Map },
{ "photo", ShopItem::Photo },
{ "umbrella", ShopItem::Umbrella },
{ "voucher", ShopItem::Voucher },
{ "hat", ShopItem::Hat },
{ "tshirt", ShopItem::TShirt },
{ "sunglasses", ShopItem::Sunglasses },
};
ShopItem RideObject::ParseShopItem(const std::string& s)
{
static const std::unordered_map<std::string, ShopItem> LookupTable{
{ "burger", ShopItem::Burger },
{ "chips", ShopItem::Chips },
{ "ice_cream", ShopItem::IceCream },
{ "candyfloss", ShopItem::Candyfloss },
{ "pizza", ShopItem::Pizza },
{ "popcorn", ShopItem::Popcorn },
{ "hot_dog", ShopItem::HotDog },
{ "tentacle", ShopItem::Tentacle },
{ "toffee_apple", ShopItem::ToffeeApple },
{ "doughnut", ShopItem::Doughnut },
{ "chicken", ShopItem::Chicken },
{ "pretzel", ShopItem::Pretzel },
{ "funnel_cake", ShopItem::FunnelCake },
{ "beef_noodles", ShopItem::BeefNoodles },
{ "fried_rice_noodles", ShopItem::FriedRiceNoodles },
{ "wonton_soup", ShopItem::WontonSoup },
{ "meatball_soup", ShopItem::MeatballSoup },
{ "sub_sandwich", ShopItem::SubSandwich },
{ "cookie", ShopItem::Cookie },
{ "roast_sausage", ShopItem::RoastSausage },
{ "drink", ShopItem::Drink },
{ "coffee", ShopItem::Coffee },
{ "lemonade", ShopItem::Lemonade },
{ "chocolate", ShopItem::Chocolate },
{ "iced_tea", ShopItem::IcedTea },
{ "fruit_juice", ShopItem::FruitJuice },
{ "soybean_milk", ShopItem::SoybeanMilk },
{ "sujeonggwa", ShopItem::Sujeonggwa },
{ "balloon", ShopItem::Balloon },
{ "toy", ShopItem::Toy },
{ "map", ShopItem::Map },
{ "photo", ShopItem::Photo },
{ "umbrella", ShopItem::Umbrella },
{ "voucher", ShopItem::Voucher },
{ "hat", ShopItem::Hat },
{ "tshirt", ShopItem::TShirt },
{ "sunglasses", ShopItem::Sunglasses },
};
auto result = LookupTable.find(s);
return (result != LookupTable.end()) ? result->second : ShopItem::None;
auto result = ShopItemLookupTable.find(s);
return (result != ShopItemLookupTable.end()) ? result->second : ShopItem::None;
}

View File

@@ -12,6 +12,7 @@
#ifdef ENABLE_SCRIPTING
# include "../core/Console.hpp"
# include "../core/EnumMap.hpp"
# include "../ride/Vehicle.h"
# include "../world/Map.h"
@@ -221,42 +222,7 @@ namespace OpenRCT2::Scripting
/**
* Bi-directional map for converting between strings and enums / numbers.
*/
template<typename T> class DukEnumMap
{
private:
std::unordered_map<std::string_view, T> _s2n;
std::unordered_map<T, std::string_view> _n2s;
public:
DukEnumMap(const std::initializer_list<std::pair<std::string_view, T>>& items)
{
_s2n = std::unordered_map<std::string_view, T>(items.begin(), items.end());
for (const auto& kvp : items)
{
_n2s.emplace(std::get<1>(kvp), std::get<0>(kvp));
}
}
std::string_view operator[](T k) const
{
auto it = _n2s.find(k);
if (it == _n2s.end())
{
return "";
}
return it->second;
}
T operator[](std::string_view k) const
{
auto it = _s2n.find(k);
if (it == _s2n.end())
{
return static_cast<T>(0);
}
return it->second;
}
};
template<typename T> using DukEnumMap = EnumMap<T>;
inline duk_ret_t duk_json_decode_wrapper(duk_context* ctx, void*)
{

View File

@@ -11,29 +11,31 @@
# include "HookEngine.h"
# include "../core/EnumMap.hpp"
# include "ScriptEngine.h"
# include <unordered_map>
using namespace OpenRCT2::Scripting;
static const EnumMap<HOOK_TYPE> HooksLookupTable({
{ "action.query", HOOK_TYPE::ACTION_QUERY },
{ "action.execute", HOOK_TYPE::ACTION_EXECUTE },
{ "interval.tick", HOOK_TYPE::INTERVAL_TICK },
{ "interval.day", HOOK_TYPE::INTERVAL_DAY },
{ "network.chat", HOOK_TYPE::NETWORK_CHAT },
{ "network.authenticate", HOOK_TYPE::NETWORK_AUTHENTICATE },
{ "network.join", HOOK_TYPE::NETWORK_JOIN },
{ "network.leave", HOOK_TYPE::NETWORK_LEAVE },
{ "ride.ratings.calculate", HOOK_TYPE::RIDE_RATINGS_CALCULATE },
{ "action.location", HOOK_TYPE::ACTION_LOCATION },
{ "guest.generation", HOOK_TYPE::GUEST_GENERATION },
});
HOOK_TYPE OpenRCT2::Scripting::GetHookType(const std::string& name)
{
static const std::unordered_map<std::string, HOOK_TYPE> LookupTable({
{ "action.query", HOOK_TYPE::ACTION_QUERY },
{ "action.execute", HOOK_TYPE::ACTION_EXECUTE },
{ "interval.tick", HOOK_TYPE::INTERVAL_TICK },
{ "interval.day", HOOK_TYPE::INTERVAL_DAY },
{ "network.chat", HOOK_TYPE::NETWORK_CHAT },
{ "network.authenticate", HOOK_TYPE::NETWORK_AUTHENTICATE },
{ "network.join", HOOK_TYPE::NETWORK_JOIN },
{ "network.leave", HOOK_TYPE::NETWORK_LEAVE },
{ "ride.ratings.calculate", HOOK_TYPE::RIDE_RATINGS_CALCULATE },
{ "action.location", HOOK_TYPE::ACTION_LOCATION },
{ "guest.generation", HOOK_TYPE::GUEST_GENERATION },
});
auto result = LookupTable.find(name);
return (result != LookupTable.end()) ? result->second : HOOK_TYPE::UNDEFINED;
auto result = HooksLookupTable.find(name);
return (result != HooksLookupTable.end()) ? result->second : HOOK_TYPE::UNDEFINED;
}
HookEngine::HookEngine(ScriptEngine& scriptEngine)

View File

@@ -17,6 +17,7 @@
# include "../actions/RideCreateAction.h"
# include "../actions/StaffHireNewAction.h"
# include "../config/Config.h"
# include "../core/EnumMap.hpp"
# include "../core/File.h"
# include "../core/FileScanner.h"
# include "../core/Path.hpp"
@@ -987,7 +988,8 @@ public:
}
};
const static std::unordered_map<std::string, GameCommand> ActionNameToType = {
// clang-format off
const static EnumMap<GameCommand> ActionNameToType = {
{ "balloonpress", GameCommand::BalloonPress },
{ "bannerplace", GameCommand::PlaceBanner },
{ "bannerremove", GameCommand::RemoveBanner },
@@ -1067,21 +1069,21 @@ const static std::unordered_map<std::string, GameCommand> ActionNameToType = {
{ "waterraise", GameCommand::RaiseWater },
{ "watersetheight", GameCommand::SetWaterHeight }
};
// clang-format on
static std::string GetActionName(GameCommand commandId)
{
auto it = std::find_if(
ActionNameToType.begin(), ActionNameToType.end(), [commandId](const auto& kvp) { return kvp.second == commandId; });
auto it = ActionNameToType.find(commandId);
if (it != ActionNameToType.end())
{
return it->first;
return std::string{ it->first };
}
return {};
}
static std::unique_ptr<GameAction> CreateGameActionFromActionId(const std::string& actionid)
static std::unique_ptr<GameAction> CreateGameActionFromActionId(const std::string& name)
{
auto result = ActionNameToType.find(actionid);
auto result = ActionNameToType.find(name);
if (result != ActionNameToType.end())
{
return GameActions::Create(result->second);

View File

@@ -248,3 +248,12 @@ SET_CHECK_CXX_FLAGS(test_s6importexporttests)
target_link_libraries(test_s6importexporttests ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_s6importexporttests)
add_test(NAME s6importexporttests COMMAND test_s6importexporttests)
# EnumMap Test
set(ENUMMAP_TEST_SOURCES "${CMAKE_CURRENT_LIST_DIR}/EnumMapTest.cpp.cpp"
"${CMAKE_CURRENT_LIST_DIR}/TestData.cpp")
add_executable(test_enummap ${S6IMPORTEXPORT_TEST_SOURCES})
SET_CHECK_CXX_FLAGS(test_enummap)
target_link_libraries(test_enummap ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_enummap)
add_test(NAME enummaptests COMMAND test_enummap)

146
test/tests/EnumMapTest.cpp Normal file
View File

@@ -0,0 +1,146 @@
/*****************************************************************************
* Copyright (c) 2014-2021 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <gtest/gtest.h>
#include <openrct2/core/EnumMap.hpp>
enum class TestEnumClassContinuous
{
A,
B,
C,
D,
E,
F,
G
};
enum class TestEnumClassNonContinuous
{
A = 1,
B,
C = 7,
D,
E,
F,
G
};
template<typename TEnum> void TestEnumKeyLookup()
{
// clang-format off
EnumMap<TEnum> enumMap = {
{ "A", TEnum::A },
{ "B", TEnum::B },
{ "C", TEnum::C },
{ "D", TEnum::D },
{ "E", TEnum::E },
{ "F", TEnum::F },
{ "G", TEnum::G },
};
// clang-format on
ASSERT_EQ(enumMap.find("Z"), enumMap.end());
auto itA = enumMap.find("A");
ASSERT_NE(itA, enumMap.end());
ASSERT_EQ(itA->second, TEnum::A);
auto itB = enumMap.find("B");
ASSERT_NE(itB, enumMap.end());
ASSERT_EQ(itB->second, TEnum::B);
auto itC = enumMap.find("C");
ASSERT_NE(itC, enumMap.end());
ASSERT_EQ(itC->second, TEnum::C);
auto itD = enumMap.find("D");
ASSERT_NE(itD, enumMap.end());
ASSERT_EQ(itD->second, TEnum::D);
auto itE = enumMap.find("E");
ASSERT_NE(itE, enumMap.end());
ASSERT_EQ(itE->second, TEnum::E);
auto itF = enumMap.find("F");
ASSERT_NE(itF, enumMap.end());
ASSERT_EQ(itF->second, TEnum::F);
auto itG = enumMap.find("G");
ASSERT_NE(itG, enumMap.end());
ASSERT_EQ(itG->second, TEnum::G);
SUCCEED();
}
template<typename TEnum> void TestEnumValueLookup()
{
// clang-format off
EnumMap<TEnum> enumMap = {
{ "A", TEnum::A },
{ "B", TEnum::B },
{ "C", TEnum::C },
{ "D", TEnum::D },
{ "E", TEnum::E },
{ "F", TEnum::F },
{ "G", TEnum::G },
};
// clang-format on
ASSERT_EQ(enumMap.find("Z"), enumMap.end());
auto itA = enumMap.find(TEnum::A);
ASSERT_NE(itA, enumMap.end());
ASSERT_EQ(itA->second, TEnum::A);
auto itB = enumMap.find(TEnum::B);
ASSERT_NE(itB, enumMap.end());
ASSERT_EQ(itB->second, TEnum::B);
auto itC = enumMap.find(TEnum::C);
ASSERT_NE(itC, enumMap.end());
ASSERT_EQ(itC->second, TEnum::C);
auto itD = enumMap.find(TEnum::D);
ASSERT_NE(itD, enumMap.end());
ASSERT_EQ(itD->second, TEnum::D);
auto itE = enumMap.find(TEnum::E);
ASSERT_NE(itE, enumMap.end());
ASSERT_EQ(itE->second, TEnum::E);
auto itF = enumMap.find(TEnum::F);
ASSERT_NE(itF, enumMap.end());
ASSERT_EQ(itF->second, TEnum::F);
auto itG = enumMap.find(TEnum::G);
ASSERT_NE(itG, enumMap.end());
ASSERT_EQ(itG->second, TEnum::G);
SUCCEED();
}
TEST(EnumMapTest, LookupContinuousByKey)
{
TestEnumKeyLookup<TestEnumClassContinuous>();
}
TEST(EnumMapTest, LookupContinuousByValue)
{
TestEnumValueLookup<TestEnumClassContinuous>();
}
TEST(EnumMapTest, LookupNonContinuousByKey)
{
TestEnumKeyLookup<TestEnumClassNonContinuous>();
}
TEST(EnumMapTest, LookupNonContinuousByValue)
{
TestEnumValueLookup<TestEnumClassNonContinuous>();
}

View File

@@ -60,6 +60,7 @@
<ClCompile Include="CLITests.cpp" />
<ClCompile Include="CryptTests.cpp" />
<ClCompile Include="Endianness.cpp" />
<ClCompile Include="EnumMapTest.cpp" />
<ClCompile Include="FormattingTests.cpp" />
<ClCompile Include="LanguagePackTest.cpp" />
<ClCompile Include="ImageImporterTests.cpp" />