mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-05-25 23:45:11 -04:00
Disabled (but not removed) mapping of old OoT ap items and locations. Not tested because I can't get the world to host yet :(
This commit is contained in:
@@ -9,34 +9,10 @@
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "fixed_string.hpp"
|
||||
#include "randomizerTypes.h"
|
||||
#include "static_data.h"
|
||||
#include "../game-interactor/GameInteractor.h"
|
||||
|
||||
//extern "C" {
|
||||
// #include "include/z64item.h"
|
||||
// #include "objects/gameplay_keep/gameplay_keep.h"
|
||||
// extern SaveContext gSaveContext;
|
||||
// extern PlayState* gPlayState;
|
||||
//}
|
||||
|
||||
//constexpr const char* requestedSlotData(int i)
|
||||
|
||||
using namespace fixstr; //https://github.com/unterumarmung/fixed_string
|
||||
template<fixed_string key>
|
||||
struct CallbackWrapper {
|
||||
static void SlotCallbackFunc(int id) {
|
||||
ArchipelagoClient::getInstance().add_slot_data(key, id);
|
||||
SPDLOG_TRACE("Recieved Slot data ({}, {})", key, id);
|
||||
}
|
||||
};
|
||||
|
||||
template<fixed_string key>
|
||||
auto SubscribeToSlotData() {
|
||||
AP_RegisterSlotDataIntCallback(std::string(key), CallbackWrapper<key>::SlotCallbackFunc);
|
||||
}
|
||||
|
||||
ArchipelagoClient::ArchipelagoClient() {
|
||||
std::string uuid = ap_get_uuid("uuid");
|
||||
|
||||
@@ -57,110 +33,7 @@ ArchipelagoClient& ArchipelagoClient::getInstance() {
|
||||
return Client;
|
||||
}
|
||||
|
||||
|
||||
void ArchipelagoClient::add_slot_data(std::string_view key, int id) {
|
||||
slot_data.insert(std::pair<std::string_view, int>(key, id));
|
||||
}
|
||||
|
||||
//void registerSlotCallbacks() {
|
||||
// SubscribeToSlotData<"open_forest">();
|
||||
// SubscribeToSlotData<"open_kakoriko">();
|
||||
// SubscribeToSlotData<"open_door_of_time">();
|
||||
// SubscribeToSlotData<"zora_fountain">();
|
||||
// SubscribeToSlotData<"gerudo_fortress">();
|
||||
// SubscribeToSlotData<"bridge">();
|
||||
// SubscribeToSlotData<"bridge_stones">();
|
||||
// SubscribeToSlotData<"bridge_medallions">();
|
||||
// SubscribeToSlotData<"bridge_rewards">();
|
||||
// SubscribeToSlotData<"bridge_tokens">();
|
||||
//// SubscribeToSlotData<"bridge_hearts">();
|
||||
// SubscribeToSlotData<"shuffle_ganon_bosskey">();
|
||||
// SubscribeToSlotData<"ganon_bosskey_medallions">();
|
||||
// SubscribeToSlotData<"ganon_bosskey_stones">();
|
||||
// SubscribeToSlotData<"ganon_bosskey_rewards">();
|
||||
// SubscribeToSlotData<"ganon_bosskey_tokens">();
|
||||
//// SubscribeToSlotData<"ganon_bosskey_hearts">();
|
||||
// SubscribeToSlotData<"trials">();
|
||||
// SubscribeToSlotData<"triforce_hunt">();
|
||||
// SubscribeToSlotData<"triforce_goal">();
|
||||
//// SubscribeToSlotData<"extra_triforce_percentage">();
|
||||
//// SubscribeToSlotData<"shopsanity">();
|
||||
//// SubscribeToSlotData<"shop_slots">();
|
||||
// SubscribeToSlotData<"shopsanity_prices">();
|
||||
//// SubscribeToSlotData<"tokensanity">();
|
||||
//// SubscribeToSlotData<"dungeon_shortcuts">();
|
||||
//// SubscribeToSlotData<"mq_dungeons_mode">();
|
||||
//// SubscribeToSlotData<"mq_dungeons_count">();
|
||||
//// SubscribeToSlotData<"shuffle_interior_entrances">();
|
||||
//// SubscribeToSlotData<"shuffle_grotto_entrances">();
|
||||
//// SubscribeToSlotData<"shuffle_dungeon_entrances">();
|
||||
//// SubscribeToSlotData<"shuffle_overworld_entrances">();
|
||||
//// SubscribeToSlotData<"shuffle_bosses">();
|
||||
//// SubscribeToSlotData<"key_rings">();
|
||||
//// SubscribeToSlotData<"enhance_map_compass">();
|
||||
//// SubscribeToSlotData<"shuffle_mapcompass">();
|
||||
//// SubscribeToSlotData<"shuffle_smallkeys">();
|
||||
//// SubscribeToSlotData<"shuffle_hideoutkeys">();
|
||||
//// SubscribeToSlotData<"shuffle_bosskeys">();
|
||||
//// SubscribeToSlotData<"logic_rules">();
|
||||
//// SubscribeToSlotData<"logic_no_night_tokens_without_suns_song">();
|
||||
//// SubscribeToSlotData<"warp_songs">();
|
||||
//// SubscribeToSlotData<"shuffle_song_items">();
|
||||
//// SubscribeToSlotData<"shuffle_medigoron_carpet_salesman">();
|
||||
//// SubscribeToSlotData<"shuffle_frog_song_rupees">();
|
||||
//// SubscribeToSlotData<"shuffle_scrubs">();
|
||||
//// SubscribeToSlotData<"shuffle_child_trade">();
|
||||
//// SubscribeToSlotData<"shuffle_freestanding_items">();
|
||||
//// SubscribeToSlotData<"shuffle_pots">();
|
||||
//// SubscribeToSlotData<"shuffle_crates">();
|
||||
//// SubscribeToSlotData<"shuffle_cows">();
|
||||
//// SubscribeToSlotData<"shuffle_beehives">();
|
||||
//// SubscribeToSlotData<"shuffle_kokiri_sword">();
|
||||
//// SubscribeToSlotData<"shuffle_ocarinas">();
|
||||
//// SubscribeToSlotData<"shuffle_gerudo_card">();
|
||||
//// SubscribeToSlotData<"shuffle_beans">();
|
||||
// SubscribeToSlotData<"starting_age">();
|
||||
//// SubscribeToSlotData<"bombchus_in_logic">();
|
||||
//// SubscribeToSlotData<"spawn_positions">();
|
||||
//// SubscribeToSlotData<"owl_drops">();
|
||||
// SubscribeToSlotData<"no_epona_race">();
|
||||
//// SubscribeToSlotData<"skip_some_minigame_phases">();
|
||||
// SubscribeToSlotData<"complete_mask_quest">();
|
||||
// SubscribeToSlotData<"free_scarecrow">();
|
||||
//// SubscribeToSlotData<"plant_beans">();
|
||||
// SubscribeToSlotData<"chicken_count">();
|
||||
// SubscribeToSlotData<"big_poe_count">();
|
||||
//// SubscribeToSlotData<"fae_torch_count">();
|
||||
// SubscribeToSlotData<"blue_fire_arrows">();
|
||||
// SubscribeToSlotData<"damage_multiplier">();
|
||||
//// SubscribeToSlotData<"deadly_bonks">();
|
||||
//// SubscribeToSlotData<"starting_tod">();
|
||||
//// SubscribeToSlotData<"junk_ice_traps">();
|
||||
// SubscribeToSlotData<"start_with_consumables">();
|
||||
//// SubscribeToSlotData<"adult_trade_start">();
|
||||
//}
|
||||
|
||||
bool ArchipelagoClient::start_client() {
|
||||
//switch(AP_GetConnectionStatus()) {
|
||||
// case AP_ConnectionStatus::ConnectionRefused:
|
||||
// SPDLOG_TRACE("refused");
|
||||
// break;
|
||||
// case AP_ConnectionStatus::Authenticated:
|
||||
// SPDLOG_TRACE("Authenticated");
|
||||
// break;
|
||||
// case AP_ConnectionStatus::Connected:
|
||||
// SPDLOG_TRACE("Connected");
|
||||
// break;
|
||||
// case AP_ConnectionStatus::Disconnected:
|
||||
// SPDLOG_TRACE("Disconnected");
|
||||
// break;
|
||||
//}
|
||||
|
||||
//if(AP_GetConnectionStatus() != AP_ConnectionStatus::Disconnected) {
|
||||
// SPDLOG_TRACE("AP already connected, shutting it down");
|
||||
// AP_Shutdown();
|
||||
//}
|
||||
|
||||
if(apclient != NULL) {
|
||||
apclient.reset();
|
||||
}
|
||||
@@ -203,13 +76,7 @@ bool ArchipelagoClient::start_client() {
|
||||
// todo implement me
|
||||
});
|
||||
|
||||
//apclient.set_slot_connected_handler() // todo rewrite the old slot callbacks when i'm ready to read slot data again
|
||||
//registerSlotCallbacks();
|
||||
//AP_Start();
|
||||
//AP_ConnectionStatus conn_status = AP_GetConnectionStatus();
|
||||
|
||||
save_data();
|
||||
//return conn_status == AP_ConnectionStatus::Connected;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -236,7 +103,8 @@ bool ArchipelagoClient::isConnected() {
|
||||
}
|
||||
|
||||
void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) {
|
||||
std::string_view ap_name = Rando::StaticData::SohCheckToAP[SoH_check_id];
|
||||
//std::string_view ap_name = Rando::StaticData::SohCheckToAP[SoH_check_id];
|
||||
std::string ap_name = Rando::StaticData::GetLocation(SoH_check_id)->GetName();
|
||||
if(ap_name.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -268,7 +136,7 @@ void ArchipelagoClient::on_connected() {
|
||||
|
||||
void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) {
|
||||
// call each callback
|
||||
const std::string item_name = apclient->get_item_name(recieved_item_id, "Ocarina of Time");
|
||||
const std::string item_name = apclient->get_item_name(recieved_item_id, AP_Client_consts::AP_GAME_NAME);
|
||||
ArchipelagoClient& ap_client = ArchipelagoClient::getInstance();
|
||||
if(ap_client.ItemRecievedCallback) {
|
||||
SPDLOG_TRACE("item recieved: {}, notify: {}", item_name, notify_player);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
#include "archipelago_settings_window.h"
|
||||
|
||||
#include "fixed_string.hpp"
|
||||
|
||||
#include "randomizerTypes.h"
|
||||
#include "static_data.h"
|
||||
#include <vector>
|
||||
@@ -20,7 +18,7 @@ namespace AP_Client_consts {
|
||||
static constexpr char const* SETTING_ADDRESS = "AP_server_address";
|
||||
static constexpr char const* SETTING_NAME = "AP_slot_name";
|
||||
|
||||
static constexpr char const* AP_GAME_NAME = "Ocarina of Time";
|
||||
static constexpr char const* AP_GAME_NAME = "Ocarina of Time (SoH)";
|
||||
}
|
||||
|
||||
class ArchipelagoClient{
|
||||
@@ -49,10 +47,6 @@ class ArchipelagoClient{
|
||||
const std::map<std::string, int>& get_slot_data();
|
||||
const std::vector<ApItem>& get_scouted_items();
|
||||
|
||||
void add_slot_data(std::string_view key, int id);
|
||||
|
||||
//void add_slot_data(std::string_view key, int id);
|
||||
|
||||
bool isConnected();
|
||||
void check_location(RandomizerCheck SoH_check_id);
|
||||
|
||||
@@ -90,18 +84,14 @@ class ArchipelagoClient{
|
||||
std::map<std::string, int> slot_data;
|
||||
std::set<int64_t> locations;
|
||||
std::vector<ApItem> scouted_items;
|
||||
|
||||
//void registerSlotCallbacks();
|
||||
|
||||
void save_data();
|
||||
|
||||
// callback functions
|
||||
void on_connected();
|
||||
//void on_couldntConnect(AP_ConnectionStatus connection_status);
|
||||
|
||||
void on_location_checked(int64_t location_id);
|
||||
void on_deathlink_recieved() { }; // TODO: implement me
|
||||
//void on_location_scouted(const std::list<APClient::NetworkItem>& network_items);
|
||||
|
||||
// callbacks
|
||||
std::function<void(const std::string&)> ItemRecievedCallback;
|
||||
|
||||
@@ -358,8 +358,9 @@ GetItemEntry Context::GetArchipelagoGIEntry() {
|
||||
}
|
||||
|
||||
// get the first item from the archipelago queue
|
||||
std::string_view recieved_ap_item = mAPrecieveQueue.front();
|
||||
RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item];
|
||||
std::string recieved_ap_item = mAPrecieveQueue.front();
|
||||
RandomizerGet item_id = StaticData::itemNameToEnum[recieved_ap_item];
|
||||
//RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item];
|
||||
assert(item_id != RG_NONE);
|
||||
|
||||
Item& item = StaticData::RetrieveItem(item_id);
|
||||
@@ -491,12 +492,14 @@ void Context::ParseArchipelagoItemsLocations(const std::vector<ArchipelagoClient
|
||||
}
|
||||
|
||||
for(const ArchipelagoClient::ApItem& ap_item: scouted_items) {
|
||||
const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second;
|
||||
//const RandomizerCheck rc = StaticData::APcheckToSoh.find(ap_item.locationName)->second;
|
||||
const RandomizerCheck rc = StaticData::locationNameToEnum[ap_item.locationName];
|
||||
|
||||
if(SlotName == ap_item.playerName) {
|
||||
// our item
|
||||
SPDLOG_TRACE("Populated item {} at location {}", ap_item.itemName, ap_item.locationName);
|
||||
const RandomizerGet item = StaticData::APitemToSoh.find(ap_item.itemName)->second;
|
||||
const RandomizerGet item = StaticData::itemNameToEnum[ap_item.itemName];
|
||||
//const RandomizerGet item = StaticData::APitemToSoh.find(ap_item.itemName)->second;
|
||||
itemLocationTable[rc].SetPlacedItem(item);
|
||||
} else {
|
||||
// other player item
|
||||
|
||||
@@ -1,682 +0,0 @@
|
||||
/*
|
||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
SPDX-License-Identifier: MIT
|
||||
Copyright (c) 2020 - 2020 Daniil Dudkin.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_STRING_HPP
|
||||
#define FIXED_STRING_HPP
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#define FIXSTR_VERSION_MAJOR 0
|
||||
#define FIXSTR_VERSION_MINOR 1
|
||||
#define FIXSTR_VERSION_PATCH 1
|
||||
|
||||
#define FIXSTR_CPP20_CHAR8T_PRESENT __cpp_char8_t
|
||||
#define FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT __cpp_lib_three_way_comparison
|
||||
|
||||
#define FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT (__cpp_lib_constexpr_algorithms)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FIXSTR_CPP_VERSION _MSVC_LANG
|
||||
#else
|
||||
#define FIXSTR_CPP_VERSION __cplusplus
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Note that when ICC or Clang is in use, FIXSTR_GCC_VERSION might not fully match the actual GCC version on the system.
|
||||
#define FIXSTR_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||
// According to clang documentation, version can be vendor specific
|
||||
#define FIXSTR_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
||||
|
||||
#if FIXSTR_GCC_VERSION >= 100'000 && FIXSTR_CPP_VERSION > 201703L
|
||||
#define FIXSTR_CPP20_CNTTP_PRESENT 1
|
||||
#elif __cpp_nontype_template_args >= 201911
|
||||
#define FIXSTR_CPP20_CNTTP_PRESENT 1
|
||||
#elif __cpp_nontype_template_parameter_class >= 201806
|
||||
#define FIXSTR_CPP20_CNTTP_PRESENT 1
|
||||
#else
|
||||
// Other compilers do not support cNTTP just yet
|
||||
#define FIXSTR_CPP20_CNTTP_PRESENT 0
|
||||
#endif // FIXSTR_CPP20_CNTTP_PRESENT
|
||||
|
||||
namespace fixstr
|
||||
{
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <typename InputIterator, typename OutputIterator>
|
||||
constexpr OutputIterator copy(InputIterator first, InputIterator last, OutputIterator d_first)
|
||||
{
|
||||
#if FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT
|
||||
return std::copy(first, last, d_first);
|
||||
#else
|
||||
while (first != last)
|
||||
{
|
||||
*d_first++ = *first++;
|
||||
}
|
||||
return d_first;
|
||||
#endif // FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT
|
||||
}
|
||||
|
||||
template <typename ForwardIterator, typename T>
|
||||
constexpr void fill(ForwardIterator first, ForwardIterator last, const T& value)
|
||||
{
|
||||
#if FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT
|
||||
std::fill(first, last, value);
|
||||
#else
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
*first = value;
|
||||
}
|
||||
#endif // FIXSTR_CPP20_CONSTEXPR_ALGORITHMS_PRESENT
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename TChar, std::size_t N, typename TTraits = std::char_traits<TChar>>
|
||||
struct basic_fixed_string // NOLINT(cppcoreguidelines-special-member-functions)
|
||||
{
|
||||
// exposition only
|
||||
using storage_type = std::array<TChar, N + 1>;
|
||||
storage_type _data{};
|
||||
|
||||
using traits_type = TTraits;
|
||||
using value_type = TChar;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = typename storage_type::iterator;
|
||||
using const_iterator = typename storage_type::const_iterator;
|
||||
using reverse_iterator = typename storage_type::reverse_iterator;
|
||||
using const_reverse_iterator = typename storage_type::const_reverse_iterator;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using string_view_type = std::basic_string_view<value_type, traits_type>;
|
||||
static constexpr auto npos = string_view_type::npos;
|
||||
|
||||
constexpr basic_fixed_string() noexcept = default;
|
||||
|
||||
constexpr basic_fixed_string(const value_type (&array)[N + 1]) noexcept // NOLINT(google-explicit-constructor)
|
||||
{
|
||||
details::copy(std::begin(array), std::end(array), _data.begin());
|
||||
}
|
||||
|
||||
constexpr basic_fixed_string& operator=(const value_type (&array)[N + 1]) noexcept
|
||||
{
|
||||
details::copy(std::begin(array), std::end(array), _data.begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
// iterators
|
||||
[[nodiscard]] constexpr iterator begin() noexcept { return _data.begin(); }
|
||||
[[nodiscard]] constexpr const_iterator begin() const noexcept { return _data.begin(); }
|
||||
[[nodiscard]] constexpr iterator end() noexcept { return _data.end() - 1; }
|
||||
[[nodiscard]] constexpr const_iterator end() const noexcept { return _data.end() - 1; }
|
||||
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _data.cbegin(); }
|
||||
[[nodiscard]] constexpr const_iterator cend() const noexcept { return _data.cend() - 1; }
|
||||
[[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return _data.rbegin() + 1; }
|
||||
[[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return _data.rbegin() + 1; }
|
||||
[[nodiscard]] constexpr reverse_iterator rend() noexcept { return _data.rend(); }
|
||||
[[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return _data.rend(); }
|
||||
[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return _data.crbegin() + 1; }
|
||||
[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return _data.crend(); }
|
||||
|
||||
private:
|
||||
[[nodiscard]] constexpr static bool static_empty() noexcept { return N == 0; }
|
||||
|
||||
public:
|
||||
// capacity
|
||||
[[nodiscard]] constexpr size_type size() const noexcept { return N; }
|
||||
[[nodiscard]] constexpr size_type length() const noexcept { return N; }
|
||||
[[nodiscard]] constexpr size_type max_size() const noexcept { return N; }
|
||||
[[nodiscard]] constexpr bool empty() const noexcept { return static_empty(); }
|
||||
|
||||
// element access
|
||||
[[nodiscard]] constexpr reference operator[](size_type n) { return _data[n]; }
|
||||
[[nodiscard]] constexpr const_reference operator[](size_type n) const { return _data[n]; }
|
||||
[[nodiscard]] constexpr reference at(size_type n) { return _data.at(n); }
|
||||
[[nodiscard]] constexpr const_reference at(size_type n) const { return _data.at(n); }
|
||||
|
||||
// The lack of C++20 concepts is disappointing
|
||||
// Basically what every `template<...>` line means is `requires (!empty())`
|
||||
template <typename..., bool NonEmpty = !static_empty(), typename = std::enable_if_t<NonEmpty>>
|
||||
[[nodiscard]] constexpr reference front() noexcept
|
||||
{
|
||||
return _data.front();
|
||||
}
|
||||
template <typename..., bool NonEmpty = !static_empty(), typename = std::enable_if_t<NonEmpty>>
|
||||
[[nodiscard]] constexpr const_reference front() const noexcept
|
||||
{
|
||||
return _data.front();
|
||||
}
|
||||
template <typename..., bool NonEmpty = !static_empty(), typename = std::enable_if_t<NonEmpty>>
|
||||
[[nodiscard]] constexpr reference back() noexcept
|
||||
{
|
||||
return _data[size() - 1];
|
||||
}
|
||||
template <typename..., bool NonEmpty = !static_empty(), typename = std::enable_if_t<NonEmpty>>
|
||||
[[nodiscard]] constexpr const_reference back() const noexcept
|
||||
{
|
||||
return _data[size() - 1];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer data() noexcept { return _data.data(); }
|
||||
[[nodiscard]] constexpr const_pointer data() const noexcept { return _data.data(); }
|
||||
|
||||
[[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); }
|
||||
|
||||
private:
|
||||
template <size_t M>
|
||||
using same_with_other_size = basic_fixed_string<value_type, M, traits_type>;
|
||||
|
||||
template <size_type pos, size_type count, size_type size>
|
||||
constexpr static size_type calculate_substr_size()
|
||||
{
|
||||
if constexpr (pos >= size)
|
||||
return 0;
|
||||
|
||||
constexpr size_type rcount = std::min(count, size - pos);
|
||||
|
||||
return rcount;
|
||||
}
|
||||
|
||||
template <size_type pos, size_type count>
|
||||
using substr_result_type = same_with_other_size<calculate_substr_size<pos, count, N>()>;
|
||||
|
||||
public:
|
||||
// string operations
|
||||
[[nodiscard]] constexpr operator string_view_type() const noexcept // NOLINT(google-explicit-constructor)
|
||||
{
|
||||
return {data(), N};
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <size_type pos = 0, size_type count = npos,
|
||||
typename..., bool IsPosInBounds = pos <= N, typename = std::enable_if_t<IsPosInBounds>>
|
||||
[[nodiscard]] constexpr auto substr() const noexcept
|
||||
-> substr_result_type<pos, count>
|
||||
// clang-format on
|
||||
{
|
||||
substr_result_type<pos, count> result;
|
||||
details::copy(begin() + pos, begin() + pos + result.size(), result.begin());
|
||||
return result;
|
||||
}
|
||||
|
||||
template <size_t M>
|
||||
[[nodiscard]] constexpr size_type find(const same_with_other_size<M>& str, size_type pos = 0) const noexcept
|
||||
{
|
||||
if constexpr (M > N)
|
||||
return npos;
|
||||
return sv().find(str.sv(), pos);
|
||||
}
|
||||
[[nodiscard]] constexpr size_type find(string_view_type sv, size_type pos = 0) const noexcept { return sv().find(sv, pos); }
|
||||
[[nodiscard]] constexpr size_type find(const value_type* s, size_type pos, size_type n) const { return sv().find(s, pos, n); }
|
||||
[[nodiscard]] constexpr size_type find(const value_type* s, size_type pos = 0) const { return sv().find(s, pos); }
|
||||
[[nodiscard]] constexpr size_type find(value_type c, size_type pos = 0) const noexcept { return sv().find(c, pos); }
|
||||
|
||||
template <size_t M>
|
||||
[[nodiscard]] constexpr size_type rfind(const same_with_other_size<M>& str, size_type pos = npos) const noexcept
|
||||
{
|
||||
if constexpr (M > N)
|
||||
return npos;
|
||||
return sv().rfind(str.sv(), pos);
|
||||
}
|
||||
[[nodiscard]] constexpr size_type rfind(string_view_type sv, size_type pos = npos) const noexcept { return sv().rfind(sv, pos); }
|
||||
[[nodiscard]] constexpr size_type rfind(const value_type* s, size_type pos, size_type n) const { return sv().rfind(s, pos, n); }
|
||||
[[nodiscard]] constexpr size_type rfind(const value_type* s, size_type pos = npos) const { return sv().rfind(s, pos); }
|
||||
[[nodiscard]] constexpr size_type rfind(value_type c, size_type pos = npos) const noexcept { return sv().rfind(c, pos); }
|
||||
|
||||
template <size_t M>
|
||||
[[nodiscard]] constexpr size_type find_first_of(const same_with_other_size<M>& str, size_type pos = 0) const noexcept
|
||||
{
|
||||
if constexpr (M > N)
|
||||
return npos;
|
||||
return sv().find_first_of(str.sv(), pos);
|
||||
}
|
||||
[[nodiscard]] constexpr size_type find_first_of(string_view_type sv, size_type pos = 0) const noexcept { return sv().find_first_of(sv, pos); }
|
||||
[[nodiscard]] constexpr size_type find_first_of(const value_type* s, size_type pos, size_type n) const { return sv().find_first_of(s, pos, n); }
|
||||
[[nodiscard]] constexpr size_type find_first_of(const value_type* s, size_type pos = 0) const { return sv().find_first_of(s, pos); }
|
||||
[[nodiscard]] constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept { return sv().find_first_of(c, pos); }
|
||||
|
||||
template <size_t M>
|
||||
[[nodiscard]] constexpr size_type find_last_of(const same_with_other_size<M>& str, size_type pos = npos) const noexcept
|
||||
{
|
||||
if constexpr (M > N)
|
||||
return npos;
|
||||
return sv().find_last_of(str.sv(), pos);
|
||||
}
|
||||
[[nodiscard]] constexpr size_type find_last_of(string_view_type sv, size_type pos = npos) const noexcept { return sv().find_last_of(sv, pos); }
|
||||
[[nodiscard]] constexpr size_type find_last_of(const value_type* s, size_type pos, size_type n) const { return sv().find_last_of(s, pos, n); }
|
||||
[[nodiscard]] constexpr size_type find_last_of(const value_type* s, size_type pos = npos) const { return sv().find_last_of(s, pos); }
|
||||
[[nodiscard]] constexpr size_type find_last_of(value_type c, size_type pos = npos) const noexcept { return sv().find_last_of(c, pos); }
|
||||
|
||||
template <size_t M>
|
||||
[[nodiscard]] constexpr size_type find_first_not_of(const same_with_other_size<M>& str, size_type pos = 0) const noexcept
|
||||
{
|
||||
if constexpr (M > N)
|
||||
return npos;
|
||||
return sv().find_first_of(str.sv(), pos);
|
||||
}
|
||||
[[nodiscard]] constexpr size_type find_first_not_of(string_view_type sv, size_type pos = 0) const noexcept { return sv().find_first_not_of(sv, pos); }
|
||||
[[nodiscard]] constexpr size_type find_first_not_of(const value_type* s, size_type pos, size_type n) const { return sv().find_first_not_of(s, pos, n); }
|
||||
[[nodiscard]] constexpr size_type find_first_not_of(const value_type* s, size_type pos = 0) const { return sv().find_first_not_of(s, pos); }
|
||||
[[nodiscard]] constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept { return sv().find_first_not_of(c, pos); }
|
||||
|
||||
template <size_t M>
|
||||
[[nodiscard]] constexpr size_type find_last_not_of(const same_with_other_size<M>& str, size_type pos = npos) const noexcept
|
||||
{
|
||||
if constexpr (M > N)
|
||||
return npos;
|
||||
return sv().find_last_of(str.sv(), pos);
|
||||
}
|
||||
[[nodiscard]] constexpr size_type find_last_not_of(string_view_type sv, size_type pos = npos) const noexcept { return sv().find_last_not_of(sv, pos); }
|
||||
[[nodiscard]] constexpr size_type find_last_not_of(const value_type* s, size_type pos, size_type n) const { return sv().find_last_not_of(s, pos, n); }
|
||||
[[nodiscard]] constexpr size_type find_last_not_of(const value_type* s, size_type pos = npos) const { return sv().find_last_not_of(s, pos); }
|
||||
[[nodiscard]] constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept { return sv().find_last_not_of(c, pos); }
|
||||
|
||||
[[nodiscard]] constexpr int compare(string_view_type v) const noexcept { return sv().compare(v); }
|
||||
[[nodiscard]] constexpr int compare(size_type pos1, size_type count1, string_view_type v) const { return sv().compare(pos1, count1, v); }
|
||||
[[nodiscard]] constexpr int compare(size_type pos1, size_type count1, string_view_type v, size_type pos2, size_type count2) const
|
||||
{
|
||||
return sv().compare(pos1, count1, v, pos2, count2);
|
||||
}
|
||||
[[nodiscard]] constexpr int compare(const value_type* s) const { return sv().compare(s); }
|
||||
[[nodiscard]] constexpr int compare(size_type pos1, size_type count1, const value_type* s) const { return sv().compare(pos1, count1, s); }
|
||||
[[nodiscard]] constexpr int compare(size_type pos1, size_type count1, const value_type* s, size_type count2) const
|
||||
{
|
||||
return sv().compare(pos1, count1, s, count2);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool starts_with(string_view_type v) const noexcept { return sv().substr(0, v.size()) == v; }
|
||||
[[nodiscard]] constexpr bool starts_with(char c) const noexcept { return !empty() && traits_type::eq(front(), c); }
|
||||
[[nodiscard]] constexpr bool starts_with(const value_type* s) const noexcept { return starts_with(string_view_type(s)); }
|
||||
|
||||
[[nodiscard]] constexpr bool ends_with(string_view_type sv) const noexcept { return size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0; }
|
||||
[[nodiscard]] constexpr bool ends_with(value_type c) const noexcept { return !empty() && traits_type::eq(back(), c); }
|
||||
[[nodiscard]] constexpr bool ends_with(const value_type* s) const { return ends_with(string_view_type(s)); }
|
||||
|
||||
[[nodiscard]] constexpr bool contains(string_view_type sv) const noexcept { return find(sv) != npos; }
|
||||
[[nodiscard]] constexpr bool contains(value_type c) const noexcept { return find(c) != npos; }
|
||||
[[nodiscard]] constexpr bool contains(const value_type* s) const { return find(s) != npos; }
|
||||
|
||||
void swap(basic_fixed_string& other) noexcept(std::is_nothrow_swappable_v<storage_type>) { _data.swap(other._data); }
|
||||
|
||||
private:
|
||||
constexpr string_view_type sv() const { return *this; }
|
||||
};
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
void swap(basic_fixed_string<TChar, N, TTraits>& lhs, basic_fixed_string<TChar, N, TTraits>& rhs) noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr bool operator==(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
if constexpr (M1 != M2)
|
||||
return false;
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) == rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator==(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) == rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator==(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs == static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
#if FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr auto operator<=>(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) <=> rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr auto operator<=>(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) <=> rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr auto operator<=>(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs <=> static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr bool operator!=(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
if constexpr (M1 != M2)
|
||||
return true;
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) != rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator!=(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) != rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator!=(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs != static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr bool operator<(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) < rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator<(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) < rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator<(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs < static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr bool operator<=(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) <= rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator<=(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) <= rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator<=(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs <= static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr bool operator>(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) > rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator>(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) > rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator>(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs > static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t M1, size_t M2>
|
||||
[[nodiscard]] constexpr bool operator>=(const basic_fixed_string<TChar, M1, TTraits>& lhs, const basic_fixed_string<TChar, M2, TTraits>& rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) >= rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator>=(const basic_fixed_string<TChar, N, TTraits>& lhs, std::basic_string_view<TChar, TTraits> rhs)
|
||||
{
|
||||
using lhs_type = std::decay_t<decltype(lhs)>;
|
||||
using sv_type = typename lhs_type::string_view_type;
|
||||
return static_cast<sv_type>(lhs) >= rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits, size_t N>
|
||||
[[nodiscard]] constexpr bool operator>=(std::basic_string_view<TChar, TTraits> lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
using rhs_type = std::decay_t<decltype(rhs)>;
|
||||
using sv_type = typename rhs_type::string_view_type;
|
||||
return lhs >= static_cast<sv_type>(rhs);
|
||||
}
|
||||
|
||||
#endif // FIXSTR_CPP20_SPACESHIP_OPERATOR_PRESENT
|
||||
|
||||
template <typename TChar, size_t N>
|
||||
basic_fixed_string(const TChar (&)[N]) -> basic_fixed_string<TChar, N - 1>;
|
||||
|
||||
// Early GCC versions that support cNTTP were not able to deduce size_t parameter
|
||||
// of basic_fixed_string when fixed_string and other typedef were just type aliases.
|
||||
// That's why the following code is written in this way.
|
||||
template <size_t N>
|
||||
struct fixed_string : basic_fixed_string<char, N>
|
||||
{
|
||||
using basic_fixed_string<char, N>::basic_fixed_string;
|
||||
};
|
||||
template <std::size_t N>
|
||||
fixed_string(const char (&)[N]) -> fixed_string<N - 1>;
|
||||
|
||||
#if FIXSTR_CPP20_CHAR8T_PRESENT
|
||||
template <size_t N>
|
||||
struct fixed_u8string : basic_fixed_string<char8_t, N>
|
||||
{
|
||||
using basic_fixed_string<char8_t, N>::basic_fixed_string;
|
||||
};
|
||||
template <std::size_t N>
|
||||
fixed_u8string(const char8_t (&)[N]) -> fixed_u8string<N - 1>;
|
||||
#endif // FIXSTR_CPP20_CHAR8T_PRESENT
|
||||
|
||||
template <size_t N>
|
||||
struct fixed_u16string : basic_fixed_string<char16_t, N>
|
||||
{
|
||||
using basic_fixed_string<char16_t, N>::basic_fixed_string;
|
||||
};
|
||||
template <std::size_t N>
|
||||
fixed_u16string(const char16_t (&)[N]) -> fixed_u16string<N - 1>;
|
||||
|
||||
template <size_t N>
|
||||
struct fixed_u32string : basic_fixed_string<char32_t, N>
|
||||
{
|
||||
using basic_fixed_string<char32_t, N>::basic_fixed_string;
|
||||
};
|
||||
template <std::size_t N>
|
||||
fixed_u32string(const char32_t (&)[N]) -> fixed_u32string<N - 1>;
|
||||
|
||||
template <size_t N>
|
||||
struct fixed_wstring : basic_fixed_string<wchar_t, N>
|
||||
{
|
||||
using basic_fixed_string<wchar_t, N>::basic_fixed_string;
|
||||
};
|
||||
template <std::size_t N>
|
||||
fixed_wstring(const wchar_t (&)[N]) -> fixed_wstring<N - 1>;
|
||||
|
||||
template <typename TChar, size_t N, size_t M, typename TTraits>
|
||||
constexpr basic_fixed_string<TChar, N + M, TTraits> operator+(const basic_fixed_string<TChar, N, TTraits>& lhs, const basic_fixed_string<TChar, M, TTraits>& rhs)
|
||||
{
|
||||
basic_fixed_string<TChar, N + M, TTraits> result;
|
||||
details::copy(lhs.begin(), lhs.end(), result.begin());
|
||||
details::copy(rhs.begin(), rhs.end(), result.begin() + N);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename TChar, size_t N, size_t M, typename TTraits>
|
||||
constexpr basic_fixed_string<TChar, N - 1 + M, TTraits> operator+(const TChar (&lhs)[N], const basic_fixed_string<TChar, M, TTraits>& rhs)
|
||||
{
|
||||
basic_fixed_string lhs2 = lhs;
|
||||
return lhs2 + rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, size_t N, size_t M, typename TTraits>
|
||||
constexpr basic_fixed_string<TChar, N + M - 1, TTraits> operator+(const basic_fixed_string<TChar, N, TTraits>& lhs, const TChar (&rhs)[M])
|
||||
{
|
||||
basic_fixed_string rhs2 = rhs;
|
||||
return lhs + rhs2;
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
template <typename TChar>
|
||||
constexpr basic_fixed_string<TChar, 1> from_char(TChar ch)
|
||||
{
|
||||
basic_fixed_string<TChar, 1> fs;
|
||||
fs[0] = ch;
|
||||
return fs;
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
template <typename TChar, size_t N, typename TTraits>
|
||||
constexpr basic_fixed_string<TChar, N + 1, TTraits> operator+(TChar lhs, const basic_fixed_string<TChar, N, TTraits>& rhs)
|
||||
{
|
||||
return details::from_char(lhs) + rhs;
|
||||
}
|
||||
|
||||
template <typename TChar, size_t N, typename TTraits>
|
||||
constexpr basic_fixed_string<TChar, N + 1, TTraits> operator+(const basic_fixed_string<TChar, N, TTraits>& lhs, TChar rhs)
|
||||
{
|
||||
return lhs + details::from_char(rhs);
|
||||
}
|
||||
|
||||
template <typename TChar, size_t N, typename TTraits>
|
||||
std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const basic_fixed_string<TChar, N, TTraits>& str)
|
||||
{
|
||||
out << str.data();
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace fixstr
|
||||
|
||||
// hash support
|
||||
namespace std
|
||||
{
|
||||
template <size_t N>
|
||||
struct hash<fixstr::fixed_string<N>>
|
||||
{
|
||||
using argument_type = fixstr::fixed_string<N>;
|
||||
size_t operator()(const argument_type& str) const
|
||||
{
|
||||
using sv_t = typename argument_type::string_view_type;
|
||||
return std::hash<sv_t>()(static_cast<sv_t>(str));
|
||||
}
|
||||
};
|
||||
|
||||
#if FIXSTR_CPP20_CHAR8T_PRESENT
|
||||
template <size_t N>
|
||||
struct hash<fixstr::fixed_u8string<N>>
|
||||
{
|
||||
using argument_type = fixstr::fixed_u8string<N>;
|
||||
size_t operator()(const argument_type& str) const
|
||||
{
|
||||
using sv_t = typename argument_type::string_view_type;
|
||||
return std::hash<sv_t>()(static_cast<sv_t>(str));
|
||||
}
|
||||
};
|
||||
#endif // FIXSTR_CPP20_CHAR8T_PRESENT
|
||||
|
||||
template <size_t N>
|
||||
struct hash<fixstr::fixed_u16string<N>>
|
||||
{
|
||||
using argument_type = fixstr::fixed_u16string<N>;
|
||||
size_t operator()(const argument_type& str) const
|
||||
{
|
||||
using sv_t = typename argument_type::string_view_type;
|
||||
return std::hash<sv_t>()(static_cast<sv_t>(str));
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct hash<fixstr::fixed_u32string<N>>
|
||||
{
|
||||
using argument_type = fixstr::fixed_u32string<N>;
|
||||
size_t operator()(const argument_type& str) const
|
||||
{
|
||||
using sv_t = typename argument_type::string_view_type;
|
||||
return std::hash<sv_t>()(static_cast<sv_t>(str));
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
struct hash<fixstr::fixed_wstring<N>>
|
||||
{
|
||||
using argument_type = fixstr::fixed_wstring<N>;
|
||||
size_t operator()(const argument_type& str) const
|
||||
{
|
||||
using sv_t = typename argument_type::string_view_type;
|
||||
return std::hash<sv_t>()(static_cast<sv_t>(str));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // FIXED_STRING_HPP
|
||||
Reference in New Issue
Block a user