Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ThirdEyeSqueegee committed Sep 9, 2023
1 parent adc2721 commit ec91db8
Show file tree
Hide file tree
Showing 15 changed files with 279 additions and 150 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/clang-format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: clang-format

on:
push:
branches: main

jobs:
maintenance:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@latest

- name: Run clang-format
uses: DoozyX/clang-format-lint-action@latest
with:
source: "."
extensions: "h, cpp"
clangFormatVersion: 16
inplace: true

- name: Add & Commit
uses: EndBug/add-and-commit@latest
with:
message: "ci: formatting"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ message("Using toolchain file ${CMAKE_TOOLCHAIN_FILE}.")
########################################################################################################################
project(
ContainerItemDistributor
VERSION 1.1.0
VERSION 1.1.1
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
6 changes: 3 additions & 3 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@
"cmakeExecutable": "C:/Program Files/CMake/bin/",
"environment": {
"COMMONLIBSSE_COMPILER": "/cgthreads8 /diagnostics:caret /EHsc /fp:contract /fp:except- /guard:cf- /MP /permissive- /sdl /W4 /Zc:__cplusplus /Zc:enumTypes /Zc:lambda /Zc:preprocessor /Zc:referenceBinding /Zc:rvalueCast /Zc:templateScope /Zc:ternary",
"COMMONLIBSSE_LINKER": "/CGTHREADS:8 /MACHINE:x64"
"COMMONLIBSSE_LINKER": "/CGTHREADS:8 /MACHINE:x64 /DEBUG:FULL"
},
"cacheVariables": {
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/fp:fast /GL /GR- /Gw /O2 /Ob3 /Qpar",
"CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO": "/DEBUG:FULL /LTCG:INCREMENTAL /OPT:REF,ICF=4",
"CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO": "/LTCG:INCREMENTAL /OPT:REF,ICF=4",
"CMAKE_CXX_FLAGS_DEBUG": "/Od /MDd",
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG:FULL /LTCG:INCREMENTAL /DEBUGTYPE:FIXUP"
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUGTYPE:FIXUP"
},
"vendor": {
"microsoft.com/VisualStudioSettings/CMake/1.0": {
Expand Down
50 changes: 33 additions & 17 deletions include/Maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@

#include "parallel_hashmap/phmap.h"

static constexpr auto is_present{ [](const std::size_t idx) { return idx <=> std::string::npos != 0; } };

static constexpr auto to_int32{ [](const std::string_view& s) { return static_cast<std::int32_t>(std::strtol(s.data(), nullptr, 0)); } };

static constexpr auto to_uint32{ [](const std::string_view& s) { return static_cast<std::uint32_t>(std::strtol(s.data(), nullptr, 0)); } };

enum class DistrType
{
Add,
Expand Down Expand Up @@ -42,13 +36,15 @@ class Container

RE::TESContainer* container{};
RE::FormID container_form_id{};
RE::FormType container_type{};
std::string container_name{};
};

struct DistrObject
{
DistrType type{};
RE::TESBoundObject* bound_object{};
std::string filename{};
std::optional<std::int32_t> count{};
std::optional<RE::TESBoundObject*> replace_with_object{};
std::optional<std::int32_t> replace_with_count{};
Expand All @@ -57,17 +53,33 @@ struct DistrObject

struct FormIDAndPluginName
{
RE::FormID form_id;
std::string plugin_name;
RE::FormID form_id{};
std::string plugin_name{};
};

class Maps : public Singleton<Maps>
{
public:
static std::int32_t ToInt32(const std::string_view& s)
{
return static_cast<std::int32_t>(std::strtol(s.data(), nullptr, 0));
}

static std::uint32_t ToUint32(const std::string_view& s)
{
return static_cast<std::uint32_t>(std::strtol(s.data(), nullptr, 0));
}

static std::size_t GetPos(const std::string_view s, const char c)
{
const auto ptr{ std::strrchr(s.data(), c) };

return static_cast<std::size_t>(ptr - s.data());
}

using TDistrTokenVec = std::vector<DistrToken>;
using TConflictTestMap = phmap::parallel_flat_hash_map<std::string, TDistrTokenVec>;

// Container EditorIDs (or FormIDs) to DistrToken vectors
inline static TConflictTestMap add_conflict_test_map;

inline static TConflictTestMap remove_conflict_test_map;
Expand All @@ -78,6 +90,7 @@ class Maps : public Singleton<Maps>
inline static TDistrVec distr_object_vec;
};

// fmt helpers
inline auto format_as(const DistrType& type)
{
switch (type)
Expand All @@ -100,17 +113,20 @@ inline auto format_as(const DistrType& type)
inline auto format_as(const DistrToken& token)
{
const auto& [type, filename, to_identifier, identifier, count, rhs, rhs_count]{ token };
return fmt::format("Type: {} / Filename: {} / To: {} / Identifier: {} / Count: {} / RHS: {} / RHS Count: {}", type, filename, to_identifier,
return fmt::format("[Type: {} / Filename: {} / To: {} / Identifier: {} / Count: {} / RHS: {} / RHS Count: {}]", type, filename, to_identifier,
identifier, count.value_or(-1), rhs.value_or("null"), rhs_count.value_or(-1));
}

inline auto format_as(const DistrObject& obj)
{
const auto& [type, bound_object, count, replace_with_obj, replace_with_count, container]{ obj };
return fmt::format("Type: {} / Bound object: {} (0x{:x}) / Count: {} / Replace with: {} (0x{:x}) / Replace count: {} / Container: {} (0x{:x})",
type, bound_object ? bound_object->GetName() : "null", bound_object ? bound_object->GetFormID() : 0, count.value_or(-1),
replace_with_obj.has_value() ? (replace_with_obj.value() ? replace_with_obj.value()->GetName() : "null") : "null",
replace_with_obj.has_value() ? (replace_with_obj.value() ? replace_with_obj.value()->GetFormID() : 0) : 0,
replace_with_count.value_or(-1), container.has_value() ? container.value().container_name : "null",
container.has_value() ? container.value().container_form_id : 0);
const auto& [type, bound_object, filename, count, replace_with_obj, replace_with_count, container]{ obj };
// clang-format off
return
fmt::format(
"[Type: {} / Filename: {} / Bound object: {} (0x{:x}) / Count: {} / Replace with: {} (0x{:x}) / Replace count: {} / Container: {} (0x{:x}) ({})]",
type, filename, bound_object ? bound_object->GetName() : "null", bound_object ? bound_object->GetFormID() : 0, count.value_or(-1),
replace_with_obj.has_value() ? (replace_with_obj.value() ? replace_with_obj.value()->GetName() : "null") : "null",
replace_with_obj.has_value() ? (replace_with_obj.value() ? replace_with_obj.value()->GetFormID() : 0) : 0, replace_with_count.value_or(-1),
container.has_value() ? container.value().container_name : "null", container.has_value() ? container.value().container_form_id : 0, container.has_value() ? container->container_type : RE::FormType::Container);
// clang-format on
}
4 changes: 2 additions & 2 deletions include/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
class Parser : public Singleton<Parser>
{
public:
static constexpr DistrType ClassifyString(const std::string_view& str) noexcept;
static DistrType ClassifyString(std::string_view str) noexcept;

static void ParseINIs(CSimpleIniA& ini) noexcept;

static DistrToken Tokenize(const std::string& str, const std::string& to) noexcept;
static DistrToken Tokenize(const std::string& str, std::string_view to_container) noexcept;
};
94 changes: 53 additions & 41 deletions include/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,84 @@

#include "Maps.h"

static constexpr auto is_editor_id{ [](const std::string_view& identifier) { return identifier.find('~') <=> std::string::npos == 0; } };

static constexpr auto get_form_id_and_plugin_name{ [](const std::string_view& identifier) {
const auto tilde{ identifier.find('~') };
return FormIDAndPluginName{ to_uint32(identifier.substr(0, tilde)), identifier.substr(tilde + 1).data() };
} };

static constexpr auto get_bound_object{ [](const std::string_view& identifier) -> RE::TESBoundObject* {
if (is_editor_id(identifier))
class Utility : public Singleton<Utility>
{
static bool IsEditorID(const std::string_view identifier)
{
if (const auto obj{ RE::TESForm::LookupByEditorID<RE::TESBoundObject>(identifier) })
return obj;
return std::strchr(identifier.data(), '~') == nullptr;
}
else

static FormIDAndPluginName GetFormIDAndPluginName(const std::string_view identifier)
{
const auto handler{ RE::TESDataHandler::GetSingleton() };
const auto [form_id, plugin_name]{ get_form_id_and_plugin_name(identifier) };
if (const auto obj{ handler->LookupForm(form_id, plugin_name) })
if (const auto tilde{ std::strchr(identifier.data(), '~') })
{
if (const auto bound_obj{ obj->As<RE::TESBoundObject>() })
return bound_obj;
const auto tilde_pos{ static_cast<int>(tilde - identifier.data()) };
return { Maps::ToUint32(identifier.substr(0, tilde_pos)), identifier.substr(tilde_pos + 1).data() };
}
return { 0, "" };
}
return nullptr;
} };

static constexpr auto get_container{ [](const std::string_view& to_identifier) {
if (is_editor_id(to_identifier))
static RE::TESBoundObject* GetBoundObject(const std::string_view identifier)
{
if (const auto form{ RE::TESForm::LookupByEditorID(to_identifier) })
if (IsEditorID(identifier))
{
if (const auto cont{ form->As<RE::TESContainer>() })
return Container{ cont, form->GetFormID(), form->GetName() };
if (const auto obj{ RE::TESForm::LookupByEditorID<RE::TESBoundObject>(identifier) })
return obj;
}
else
{
const auto handler{ RE::TESDataHandler::GetSingleton() };
const auto [form_id, plugin_name]{ GetFormIDAndPluginName(identifier) };
if (const auto obj{ handler->LookupForm(form_id, plugin_name) })
{
if (const auto bound_obj{ obj->As<RE::TESBoundObject>() })
return bound_obj;
}
}
return nullptr;
}
else

static Container GetContainer(const std::string_view to_identifier)
{
const auto handler{ RE::TESDataHandler::GetSingleton() };
const auto [form_id, plugin_name]{ get_form_id_and_plugin_name(to_identifier) };
if (const auto form{ handler->LookupForm(form_id, plugin_name) })
if (IsEditorID(to_identifier))
{
if (const auto cont{ form->As<RE::TESContainer>() })
return Container{ cont, form->GetFormID(), form->GetName() };
if (const auto form{ RE::TESForm::LookupByEditorID(to_identifier) })
{
if (const auto cont{ form->As<RE::TESContainer>() })
return { cont, form->GetFormID(), form->GetFormType(), form->GetName() };
}
}
else
{
const auto handler{ RE::TESDataHandler::GetSingleton() };
const auto [form_id, plugin_name]{ GetFormIDAndPluginName(to_identifier) };
if (const auto form{ handler->LookupForm(form_id, plugin_name) })
{
if (const auto cont{ form->As<RE::TESContainer>() })
return { cont, form->GetFormID(), form->GetFormType(), form->GetName() };
}
}
return { nullptr, 0, RE::FormType::Container, "" };
}
return Container{ nullptr, 0, "" };
} };

class Utility : public Singleton<Utility>
{
public:
static constexpr DistrObject BuildDistrObject(const DistrToken& distr_token) noexcept
static DistrObject BuildDistrObject(const DistrToken& distr_token) noexcept
{
if (const auto bound_obj{ get_bound_object(distr_token.identifier) })
if (const auto bound_obj{ GetBoundObject(distr_token.identifier) })
{
if (const auto cont{ get_container(distr_token.to_identifier) }; cont.container)
if (const auto cont{ GetContainer(distr_token.to_identifier) }; cont.container)
{
if (distr_token.type <=> DistrType::Replace == 0 || distr_token.type <=> DistrType::ReplaceAll == 0)
{
if (const auto replace_with_obj{ get_bound_object(distr_token.rhs.value()) })
return { distr_token.type, bound_obj, distr_token.count, replace_with_obj, distr_token.rhs_count, cont };
if (const auto replace_with_obj{ GetBoundObject(distr_token.rhs.value()) })
return {
distr_token.type, bound_obj, distr_token.filename, distr_token.count, replace_with_obj, distr_token.rhs_count, cont
};
}
return { distr_token.type, bound_obj, distr_token.count, std::nullopt, std::nullopt, cont };
return { distr_token.type, bound_obj, distr_token.filename, distr_token.count, std::nullopt, std::nullopt, cont };
}
}

return { DistrType::Error, nullptr, std::nullopt, std::nullopt, std::nullopt, std::nullopt };
return { DistrType::Error, nullptr, distr_token.filename, std::nullopt, std::nullopt, std::nullopt, std::nullopt };
}
};
42 changes: 24 additions & 18 deletions include/parallel_hashmap/phmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -1268,21 +1268,16 @@ class raw_hash_set
size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }

PHMAP_ATTRIBUTE_REINITIALIZES void clear() {
// Iterating over this container is O(bucket_count()). When bucket_count()
// is much greater than size(), iteration becomes prohibitively expensive.
// For clear() it is more important to reuse the allocated array when the
// container is small because allocation takes comparatively long time
// compared to destruction of the elements of the container. So we pick the
// largest bucket_count() threshold for which iteration is still fast and
// past that we simply deallocate the array.
if (empty())
return;
if (capacity_ > 127) {
destroy_slots();
} else if (capacity_) {
for (size_t i = 0; i != capacity_; ++i) {
if (IsFull(ctrl_[i])) {
PolicyTraits::destroy(&alloc_ref(), slots_ + i);
if (capacity_) {
if constexpr (!std::is_trivially_destructible<typename PolicyTraits::value_type>::value ||
std::is_same<typename Policy::is_flat, std::false_type>::value) {
// node map or not trivially destructible... we need to iterate and destroy values one by one
for (size_t i = 0; i != capacity_; ++i) {
if (IsFull(ctrl_[i])) {
PolicyTraits::destroy(&alloc_ref(), slots_ + i);
}
}
}
size_ = 0;
Expand Down Expand Up @@ -2011,12 +2006,19 @@ class raw_hash_set
}

void destroy_slots() {
if (!capacity_) return;
for (size_t i = 0; i != capacity_; ++i) {
if (IsFull(ctrl_[i])) {
PolicyTraits::destroy(&alloc_ref(), slots_ + i);
if (!capacity_)
return;

if constexpr (!std::is_trivially_destructible<typename PolicyTraits::value_type>::value ||
std::is_same<typename Policy::is_flat, std::false_type>::value) {
// node map, or not trivially destructible... we need to iterate and destroy values one by one
// std::cout << "either this is a node map or " << type_name<typename PolicyTraits::value_type>() << " is not trivially_destructible\n";
for (size_t i = 0; i != capacity_; ++i) {
if (IsFull(ctrl_[i])) {
PolicyTraits::destroy(&alloc_ref(), slots_ + i);
}
}
}
}
auto layout = MakeLayout(capacity_);
// Unpoison before returning the memory to the allocator.
SanitizerUnpoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
Expand Down Expand Up @@ -4184,6 +4186,7 @@ struct FlatHashSetPolicy
using key_type = T;
using init_type = T;
using constant_iterators = std::true_type;
using is_flat = std::true_type;

template <class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
Expand Down Expand Up @@ -4226,6 +4229,7 @@ struct FlatHashMapPolicy
using key_type = K;
using mapped_type = V;
using init_type = std::pair</*non const*/ key_type, mapped_type>;
using is_flat = std::true_type;

template <class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
Expand Down Expand Up @@ -4308,6 +4312,7 @@ struct NodeHashSetPolicy
using key_type = T;
using init_type = T;
using constant_iterators = std::true_type;
using is_flat = std::false_type;

template <class Allocator, class... Args>
static T* new_element(Allocator* alloc, Args&&... args) {
Expand Down Expand Up @@ -4353,6 +4358,7 @@ class NodeHashMapPolicy
using key_type = Key;
using mapped_type = Value;
using init_type = std::pair</*non const*/ key_type, mapped_type>;
using is_flat = std::false_type;

template <class Allocator, class... Args>
static value_type* new_element(Allocator* alloc, Args&&... args) {
Expand Down
Loading

0 comments on commit ec91db8

Please sign in to comment.