aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl/string.ccm
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.ucl/string.ccm')
-rw-r--r--nihil.ucl/string.ccm196
1 files changed, 164 insertions, 32 deletions
diff --git a/nihil.ucl/string.ccm b/nihil.ucl/string.ccm
index f8dc1cd..9127b2d 100644
--- a/nihil.ucl/string.ccm
+++ b/nihil.ucl/string.ccm
@@ -5,13 +5,18 @@
module;
#include <cstdlib>
+#include <expected>
+#include <format>
+#include <iosfwd>
#include <string>
#include <ucl.h>
export module nihil.ucl:string;
+import nihil;
import :object;
+import :type;
namespace nihil::ucl {
@@ -19,6 +24,7 @@ export struct string final : object {
using contained_type = std::string_view;
inline static constexpr object_type ucl_type = object_type::string;
+ // string is a container of char
using value_type = char const;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
@@ -26,57 +32,130 @@ export struct string final : object {
using pointer = value_type *;
using iterator = pointer;
- // Create a new string from a UCL object.
- string(ref_t, ::ucl_object_t const *uobj);
- string(noref_t, ::ucl_object_t *uobj);
-
- // Create a new empty string.
+ /*
+ * Create a new empty string. Throws std::system_error on failure.
+ */
string();
- // Create a new UCL string from a string.
- explicit string(std::string_view value);
+ /*
+ * Create a string from a value. Throws std::system_error on failure.
+ */
+ explicit string(std::string_view);
+
+ /*
+ * Create a string from a C literal. Throws std::system_error
+ * on failure.
+ */
+ explicit string(char const *);
+
+ /*
+ * Create a string from a contiguous range. The range's value type
+ * must be char. Throws std::system_error on failure.
+ */
+ template<std::ranges::contiguous_range Range>
+ requires (!std::same_as<std::string_view, Range> &&
+ std::same_as<char, std::ranges::range_value_t<Range>>)
+ explicit string(Range &&range)
+ : string(std::string_view(std::ranges::begin(range),
+ std::ranges::end(range)))
+ {}
- // Create a new UCL string from an iterator pair.
- template<std::contiguous_iterator Iterator>
- string(Iterator first, Iterator last)
- : string(std::string_view(first, last))
+ /*
+ * Create a string from a non-contiguous range. This requires a
+ * temporary value due to limitations of the UCL C API.
+ */
+ template<std::ranges::range Range>
+ requires (!std::ranges::contiguous_range<Range> &&
+ std::same_as<char, std::ranges::range_value_t<Range>>)
+ explicit string(Range &&range)
+ : string(std::string(std::from_range, range))
{}
+ /*
+ * Create a string from an iterator pair. The iterator's value type
+ * must be char. If the iterator pair is not contiguous, the value
+ * will be copied to a temporary first.
+ *
+ * Throws std::system_error on failure.
+ */
template<std::input_iterator Iterator>
- requires(!std::contiguous_iterator<Iterator>)
+ requires (std::same_as<char, std::iter_value_t<Iterator>>)
string(Iterator first, Iterator last)
- : string(std::string(first, last))
+ : string(std::ranges::subrange(first, last))
{}
- // Create a new UCL string from a range.
- string(std::from_range_t, std::ranges::range auto &&range)
- : string(std::ranges::begin(range),
- std::ranges::end(range))
- {}
+ /*
+ * Create a new string from a UCL object. Throws type_mismatch
+ * on failure.
+ */
+ string(ref_t, ::ucl_object_t const *uobj);
+ string(noref_t, ::ucl_object_t *uobj);
// Return the value of this string.
- auto value(this string const &self) -> contained_type;
+ [[nodiscard]] auto value(this string const &self) -> contained_type;
// Return the size of this string.
- auto size(this string const &self) -> size_type;
+ [[nodiscard]] auto size(this string const &self) -> size_type;
// Test if this string is empty.
- auto empty(this string const &self) -> bool;
+ [[nodiscard]] auto empty(this string const &self) -> bool;
// Access this string's data
- auto data(this string const &self) -> pointer;
+ [[nodiscard]] auto data(this string const &self) -> pointer;
// Iterator access
- auto begin(this string const &self) -> iterator;
- auto end(this string const &self) -> iterator;
+ [[nodiscard]] auto begin(this string const &self) -> iterator;
+ [[nodiscard]] auto end(this string const &self) -> iterator;
};
/*
+ * String constructors. These return an error instead of throwing.
+ */
+
+// Empty string
+export [[nodiscard]] auto
+make_string() -> std::expected<string, error>;
+
+// From string_view
+export [[nodiscard]] auto
+make_string(std::string_view) -> std::expected<string, error>;
+
+// From C literal
+export [[nodiscard]] auto
+make_string(char const *) -> std::expected<string, error>;
+
+// From contiguous range
+export template<std::ranges::contiguous_range Range>
+requires (!std::same_as<std::string_view, Range> &&
+ std::same_as<char, std::ranges::range_value_t<Range>>)
+[[nodiscard]] auto make_string(Range &&range)
+{
+ return make_string(std::string_view(range));
+}
+
+// From non-contiguous range
+export template<std::ranges::range Range>
+requires (!std::ranges::contiguous_range<Range> &&
+ std::same_as<char, std::ranges::range_value_t<Range>>)
+[[nodiscard]] auto make_string(Range &&range)
+{
+ return make_string(std::string(std::from_range, range));
+}
+
+// From iterator pair
+export template<std::input_iterator Iterator>
+requires (std::same_as<char, std::iter_value_t<Iterator>>)
+[[nodiscard]] auto make_string(Iterator first, Iterator last)
+{
+ return make_string(std::ranges::subrange(first, last));
+}
+
+/*
* Comparison operators.
*/
-export auto operator== (string const &a, string const &b) -> bool;
-export auto operator<=> (string const &a, string const &b)
+export [[nodiscard]] auto operator== (string const &a, string const &b) -> bool;
+export [[nodiscard]] auto operator<=> (string const &a, string const &b)
-> std::strong_ordering;
/*
@@ -84,15 +163,68 @@ export auto operator<=> (string const &a, string const &b)
* construct a temporary UCL object.
*/
-export auto operator==(string const &lhs, std::string_view rhs) -> bool;
-export auto operator==(string const &lhs, std::string const &rhs) -> bool;
-export auto operator==(string const &lhs, char const *rhs) -> bool;
+export [[nodiscard]] auto operator==(string const &lhs,
+ std::string_view rhs) -> bool;
+
+export [[nodiscard]] auto operator==(string const &lhs,
+ std::string const &rhs) -> bool;
+
+export [[nodiscard]] auto operator==(string const &lhs,
+ char const *rhs) -> bool;
-export auto operator<=>(string const &lhs, std::string_view rhs)
+export [[nodiscard]] auto operator<=>(string const &lhs,
+ std::string_view rhs)
-> std::strong_ordering;
-export auto operator<=>(string const &lhs, std::string const &rhs)
+
+export [[nodiscard]] auto operator<=>(string const &lhs,
+ std::string const &rhs)
-> std::strong_ordering;
-export auto operator<=>(string const &lhs, char const *rhs)
+
+export [[nodiscard]] auto operator<=>(string const &lhs,
+ char const *rhs)
-> std::strong_ordering;
+/*
+ * Print a string to a stream.
+ */
+export auto operator<<(std::ostream &, string const &) -> std::ostream &;
+
+/*
+ * Literal operator.
+ */
+inline namespace literals {
+ export constexpr auto operator""_ucl (char const *s, std::size_t n)
+ -> string
+ {
+ return string(std::string_view(s, n));
+ }
+} // namespace nihil::ucl::literals
+
} // namespace nihil::ucl
+
+namespace nihil { inline namespace literals {
+ export using namespace ::nihil::ucl::literals;
+}} // namespace nihil::literals
+
+/*
+ * std::formatter for a string. This provides the same format operations
+ * as std::formatter<std::string_view>.
+ */
+export template<>
+struct std::formatter<nihil::ucl::string, char>
+{
+ std::formatter<std::string_view> base_formatter;
+
+ template<class ParseContext>
+ constexpr ParseContext::iterator parse(ParseContext& ctx)
+ {
+ return base_formatter.parse(ctx);
+ }
+
+ template<class FmtContext>
+ FmtContext::iterator format(nihil::ucl::string const &o,
+ FmtContext& ctx) const
+ {
+ return base_formatter.format(o.value(), ctx);
+ }
+};