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 <spdlog/spdlog.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "fixed_string.hpp"
|
|
||||||
#include "randomizerTypes.h"
|
#include "randomizerTypes.h"
|
||||||
#include "static_data.h"
|
#include "static_data.h"
|
||||||
#include "../game-interactor/GameInteractor.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() {
|
ArchipelagoClient::ArchipelagoClient() {
|
||||||
std::string uuid = ap_get_uuid("uuid");
|
std::string uuid = ap_get_uuid("uuid");
|
||||||
|
|
||||||
@@ -57,110 +33,7 @@ ArchipelagoClient& ArchipelagoClient::getInstance() {
|
|||||||
return Client;
|
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() {
|
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) {
|
if(apclient != NULL) {
|
||||||
apclient.reset();
|
apclient.reset();
|
||||||
}
|
}
|
||||||
@@ -203,13 +76,7 @@ bool ArchipelagoClient::start_client() {
|
|||||||
// todo implement me
|
// 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();
|
save_data();
|
||||||
//return conn_status == AP_ConnectionStatus::Connected;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +103,8 @@ bool ArchipelagoClient::isConnected() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ArchipelagoClient::check_location(RandomizerCheck SoH_check_id) {
|
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()) {
|
if(ap_name.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -268,7 +136,7 @@ void ArchipelagoClient::on_connected() {
|
|||||||
|
|
||||||
void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) {
|
void ArchipelagoClient::on_item_recieved(int64_t recieved_item_id, bool notify_player) {
|
||||||
// call each callback
|
// 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();
|
ArchipelagoClient& ap_client = ArchipelagoClient::getInstance();
|
||||||
if(ap_client.ItemRecievedCallback) {
|
if(ap_client.ItemRecievedCallback) {
|
||||||
SPDLOG_TRACE("item recieved: {}, notify: {}", item_name, notify_player);
|
SPDLOG_TRACE("item recieved: {}, notify: {}", item_name, notify_player);
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "archipelago_settings_window.h"
|
#include "archipelago_settings_window.h"
|
||||||
|
|
||||||
#include "fixed_string.hpp"
|
|
||||||
|
|
||||||
#include "randomizerTypes.h"
|
#include "randomizerTypes.h"
|
||||||
#include "static_data.h"
|
#include "static_data.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -20,7 +18,7 @@ namespace AP_Client_consts {
|
|||||||
static constexpr char const* SETTING_ADDRESS = "AP_server_address";
|
static constexpr char const* SETTING_ADDRESS = "AP_server_address";
|
||||||
static constexpr char const* SETTING_NAME = "AP_slot_name";
|
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{
|
class ArchipelagoClient{
|
||||||
@@ -49,10 +47,6 @@ class ArchipelagoClient{
|
|||||||
const std::map<std::string, int>& get_slot_data();
|
const std::map<std::string, int>& get_slot_data();
|
||||||
const std::vector<ApItem>& get_scouted_items();
|
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();
|
bool isConnected();
|
||||||
void check_location(RandomizerCheck SoH_check_id);
|
void check_location(RandomizerCheck SoH_check_id);
|
||||||
|
|
||||||
@@ -91,17 +85,13 @@ class ArchipelagoClient{
|
|||||||
std::set<int64_t> locations;
|
std::set<int64_t> locations;
|
||||||
std::vector<ApItem> scouted_items;
|
std::vector<ApItem> scouted_items;
|
||||||
|
|
||||||
//void registerSlotCallbacks();
|
|
||||||
|
|
||||||
void save_data();
|
void save_data();
|
||||||
|
|
||||||
// callback functions
|
// callback functions
|
||||||
void on_connected();
|
void on_connected();
|
||||||
//void on_couldntConnect(AP_ConnectionStatus connection_status);
|
|
||||||
|
|
||||||
void on_location_checked(int64_t location_id);
|
void on_location_checked(int64_t location_id);
|
||||||
void on_deathlink_recieved() { }; // TODO: implement me
|
void on_deathlink_recieved() { }; // TODO: implement me
|
||||||
//void on_location_scouted(const std::list<APClient::NetworkItem>& network_items);
|
|
||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
std::function<void(const std::string&)> ItemRecievedCallback;
|
std::function<void(const std::string&)> ItemRecievedCallback;
|
||||||
|
|||||||
@@ -358,8 +358,9 @@ GetItemEntry Context::GetArchipelagoGIEntry() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the first item from the archipelago queue
|
// get the first item from the archipelago queue
|
||||||
std::string_view recieved_ap_item = mAPrecieveQueue.front();
|
std::string recieved_ap_item = mAPrecieveQueue.front();
|
||||||
RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item];
|
RandomizerGet item_id = StaticData::itemNameToEnum[recieved_ap_item];
|
||||||
|
//RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item];
|
||||||
assert(item_id != RG_NONE);
|
assert(item_id != RG_NONE);
|
||||||
|
|
||||||
Item& item = StaticData::RetrieveItem(item_id);
|
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) {
|
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) {
|
if(SlotName == ap_item.playerName) {
|
||||||
// our item
|
// our item
|
||||||
SPDLOG_TRACE("Populated item {} at location {}", ap_item.itemName, ap_item.locationName);
|
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);
|
itemLocationTable[rc].SetPlacedItem(item);
|
||||||
} else {
|
} else {
|
||||||
// other player item
|
// 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