Skip to content

Commit

Permalink
Factorize split_once functions
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoinePrv committed Nov 3, 2023
1 parent 95f00f2 commit 768b392
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 15 deletions.
12 changes: 12 additions & 0 deletions libmamba/include/mamba/util/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -192,6 +194,16 @@ namespace mamba::util
template <typename UnaryFunc>
std::array<std::wstring_view, 3> strip_if_parts(std::wstring_view input, UnaryFunc should_strip);

[[nodiscard]] auto split_once(std::string_view str, char sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>;
[[nodiscard]] auto split_once(std::string_view str, std::string_view sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>;

[[nodiscard]] auto rsplit_once(std::string_view str, char sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>;
[[nodiscard]] auto rsplit_once(std::string_view str, std::string_view sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>;

std::vector<std::string>
split(std::string_view input, std::string_view sep, std::size_t max_split = SIZE_MAX);
std::vector<std::wstring>
Expand Down
18 changes: 4 additions & 14 deletions libmamba/src/core/channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,16 +206,6 @@ namespace mamba
}
}

auto rsplit_once(std::string_view str, char sep)
{
auto [head, tail] = util::rstrip_if_parts(str, [sep](char c) { return c != sep; });
if (head.empty())
{
return std::array{ head, tail };
}
return std::array{ head.substr(0, head.size() - 1), tail };
}

auto
make_platforms(util::flat_set<std::string> filters, const std::vector<std::string>& defaults)
{
Expand All @@ -234,16 +224,16 @@ namespace mamba
{
auto uri = specs::CondaURL::parse(util::path_or_url_to_url(spec.location()));

auto path = uri.pretty_path();
auto [parent, current] = rsplit_once(path, '/');
auto path = util::rstrip(uri.pretty_path(), '/');
auto [parent, current] = util::rsplit_once(path, '/');
for (const auto& [canonical_name, chan] : get_custom_channels())
{
if (url_match(chan.url(), uri))
{
return Channel(
/* url= */ std::move(uri),
/* location= */ chan.url().pretty_str(specs::CondaURL::StripScheme::yes),
/* name= */ std::string(util::rstrip(parent, '/')),
/* name= */ std::string(util::rstrip(parent.value_or(""), '/')),
/* canonical_name= */ std::string(canonical_name)
);
}
Expand All @@ -263,7 +253,7 @@ namespace mamba
auto canonical_name = uri.pretty_str();
return Channel(
/* url= */ std::move(uri),
/* location= */ std::string(util::rstrip(parent, '/')),
/* location= */ std::string(util::rstrip(parent.value_or(""), '/')),
/* name= */ std::string(util::rstrip(current, '/')),
/* canonical_name= */ std::move(canonical_name)
);
Expand Down
59 changes: 59 additions & 0 deletions libmamba/src/util/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,65 @@ namespace mamba::util
return strip_parts_impl(input, chars);
}

/********************************************
* Implementation of split_once functions *
********************************************/

namespace
{
template <typename Char, typename CharOrStrView>
auto split_once_impl(std::basic_string_view<Char> str, CharOrStrView sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>
{
static constexpr auto npos = std::basic_string_view<Char>::npos;
if (const auto pos = str.find(sep); pos != npos)
{
return { str.substr(0, pos), str.substr(pos + detail::length(sep)) };
}
return { str, std::nullopt };
}
}

auto split_once(std::string_view str, char sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>
{
return split_once_impl(str, sep);
}

auto split_once(std::string_view str, std::string_view sep)
-> std::tuple<std::string_view, std::optional<std::string_view>>
{
return split_once_impl(str, sep);
}

namespace
{
template <typename Char, typename CharOrStrView>
auto rsplit_once_impl(std::basic_string_view<Char> str, CharOrStrView sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>
{
static constexpr auto npos = std::basic_string_view<Char>::npos;
if (const auto pos = str.rfind(sep); pos != npos)
{
return { str.substr(0, pos), str.substr(pos + detail::length(sep)) };
}
return { std::nullopt, str };
}
}

auto rsplit_once(std::string_view str, char sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>
{
return rsplit_once_impl(str, sep);
}

auto rsplit_once(std::string_view str, std::string_view sep)
-> std::tuple<std::optional<std::string_view>, std::string_view>
{
return rsplit_once_impl(str, sep);
}


/***************************************
* Implementation of split functions *
***************************************/
Expand Down
26 changes: 26 additions & 0 deletions libmamba/tests/src/doctest-printer/optional.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2023, QuantStack and Mamba Contributors
//
// Distributed under the terms of the BSD 3-Clause License.
//
// The full license is in the file LICENSE, distributed with this software.

#include <optional>

#include <doctest/doctest.h>
#include <fmt/format.h>

namespace doctest
{
template <typename T>
struct StringMaker<std::optional<T>>
{
static auto convert(const std::optional<T>& value) -> String
{
if (value.has_value())
{
return { fmt::format("Some({})", value.value()).c_str() };
}
return "None";
}
};
}
38 changes: 37 additions & 1 deletion libmamba/tests/src/util/test_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//
// The full license is in the file LICENSE, distributed with this software.

#include <cstddef>
#include <string>
#include <string_view>
#include <vector>
Expand All @@ -14,6 +13,9 @@
#include "mamba/fs/filesystem.hpp"
#include "mamba/util/string.hpp"

#include "doctest-printer/array.hpp"
#include "doctest-printer/optional.hpp"

namespace mamba::util
{
TEST_SUITE("util::string")
Expand Down Expand Up @@ -364,6 +366,40 @@ namespace mamba::util
}
}

TEST_CASE("split_once")
{
using Out = std::tuple<std::string_view, std::optional<std::string_view>>;

CHECK_EQ(split_once("", '/'), Out{ "", std::nullopt });
CHECK_EQ(split_once("/", '/'), Out{ "", "" });
CHECK_EQ(split_once("hello/world", '/'), Out{ "hello", "world" });
CHECK_EQ(split_once("hello/my/world", '/'), Out{ "hello", "my/world" });
CHECK_EQ(split_once("/hello/world", '/'), Out{ "", "hello/world" });

CHECK_EQ(split_once("", "/"), Out{ "", std::nullopt });
CHECK_EQ(split_once("hello/world", "/"), Out{ "hello", "world" });
CHECK_EQ(split_once("hello//world", "//"), Out{ "hello", "world" });
CHECK_EQ(split_once("hello/my//world", "/"), Out{ "hello", "my//world" });
CHECK_EQ(split_once("hello/my//world", "//"), Out{ "hello/my", "world" });
}

TEST_CASE("rsplit_once")
{
using Out = std::tuple<std::optional<std::string_view>, std::string_view>;

CHECK_EQ(rsplit_once("", '/'), Out{ std::nullopt, "" });
CHECK_EQ(rsplit_once("/", '/'), Out{ "", "" });
CHECK_EQ(rsplit_once("hello/world", '/'), Out{ "hello", "world" });
CHECK_EQ(rsplit_once("hello/my/world", '/'), Out{ "hello/my", "world" });
CHECK_EQ(rsplit_once("hello/world/", '/'), Out{ "hello/world", "" });

CHECK_EQ(rsplit_once("", "/"), Out{ std::nullopt, "" });
CHECK_EQ(rsplit_once("hello/world", "/"), Out{ "hello", "world" });
CHECK_EQ(rsplit_once("hello//world", "//"), Out{ "hello", "world" });
CHECK_EQ(rsplit_once("hello//my/world", "/"), Out{ "hello//my", "world" });
CHECK_EQ(rsplit_once("hello//my/world", "//"), Out{ "hello", "my/world" });
}

TEST_CASE("split")
{
std::string a = "hello.again.it's.me.mario";
Expand Down

0 comments on commit 768b392

Please sign in to comment.