aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.ucl
diff options
context:
space:
mode:
Diffstat (limited to 'nihil.ucl')
-rw-r--r--nihil.ucl/array.ccm39
-rw-r--r--nihil.ucl/boolean.ccm24
-rw-r--r--nihil.ucl/integer.ccm24
-rw-r--r--nihil.ucl/object.ccm56
-rw-r--r--nihil.ucl/object_cast.ccm7
-rw-r--r--nihil.ucl/parser.ccm3
-rw-r--r--nihil.ucl/real.ccm23
-rw-r--r--nihil.ucl/string.ccm46
-rw-r--r--nihil.ucl/tests/array.cc2
9 files changed, 154 insertions, 70 deletions
diff --git a/nihil.ucl/array.ccm b/nihil.ucl/array.ccm
index 7488bde..87e175e 100644
--- a/nihil.ucl/array.ccm
+++ b/nihil.ucl/array.ccm
@@ -35,7 +35,7 @@ struct array_iterator {
if (uobj == nullptr)
throw error("failed to fetch UCL array index");
- return T(::ucl_object_ref(uobj));
+ return T(nihil::ucl::ref, uobj);
}
auto operator[] (this array_iterator const &self,
@@ -158,15 +158,26 @@ struct array final : object {
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
- array() : object(::ucl_object_typed_new(UCL_ARRAY))
+ // Create an empty array.
+ array() : object(noref, ::ucl_object_typed_new(UCL_ARRAY))
{
if (_object == nullptr)
throw error("failed to create UCL object");
}
- explicit array(::ucl_object_t *uobj) : object(uobj)
+ // Create a new array from a UCL object.
+ array(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
{
- assert(type() == object_type::array);
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+ }
+
+ array(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
+ {
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
}
/*
@@ -175,7 +186,7 @@ struct array final : object {
template<std::input_iterator Iterator>
requires(std::convertible_to<std::iter_value_t<Iterator>, T>)
array(Iterator first, Iterator last)
- : object(::ucl_object_typed_new(UCL_ARRAY))
+ : array()
{
if (_object == nullptr)
throw error("failed to create UCL object");
@@ -249,14 +260,6 @@ struct array final : object {
/*
* Append an element to the array.
*/
- auto push_back(this array &self, value_type &&v) -> void
- {
- // There's no real benefit to moving the object here, but
- // move it anyway to preserve the expected semantics.
- auto copy = std::move(v);
- self.push_back(copy);
- }
-
auto push_back(this array &self, value_type const &v) -> void
{
auto uobj = ::ucl_object_ref(v.get_ucl_object());
@@ -266,14 +269,6 @@ struct array final : object {
/*
* Prepend an element to the array.
*/
- auto push_front(this array &self, value_type &&v) -> void
- {
- // There's no real benefit to moving the object here, but
- // move it anyway to preserve the expected semantics.
- auto copy = std::move(v);
- self.push_front(copy);
- }
-
auto push_front(this array &self, value_type const &v) -> void
{
auto uobj = ::ucl_object_ref(v.get_ucl_object());
@@ -292,7 +287,7 @@ struct array final : object {
if (uobj == nullptr)
throw error("failed to fetch UCL array index");
- return T(::ucl_object_ref(uobj));
+ return T(nihil::ucl::ref, uobj);
}
auto operator[] (this array const &self, size_type idx) -> T
diff --git a/nihil.ucl/boolean.ccm b/nihil.ucl/boolean.ccm
index db6c864..e9c161b 100644
--- a/nihil.ucl/boolean.ccm
+++ b/nihil.ucl/boolean.ccm
@@ -22,18 +22,30 @@ export struct boolean final : object {
inline static constexpr object_type ucl_type = object_type::boolean;
- boolean(value_type value)
- : object(::ucl_object_frombool(value))
+ // Create a new boolean from a UCL object.
+ boolean(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
{
- if (_object == nullptr)
- throw error("failed to create UCL object");
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
}
- explicit boolean(::ucl_object_t *uobj) : object(uobj)
+ boolean(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
{
- assert(type() == object_type::boolean);
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+ }
+
+ // Create a new boolean from a value.
+ explicit boolean(value_type value)
+ : object(noref, ::ucl_object_frombool(value))
+ {
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
}
+ // Return this object's value.
auto value(this boolean const &self) -> value_type
{
auto v = value_type{};
diff --git a/nihil.ucl/integer.ccm b/nihil.ucl/integer.ccm
index d3009a1..18f0049 100644
--- a/nihil.ucl/integer.ccm
+++ b/nihil.ucl/integer.ccm
@@ -22,18 +22,30 @@ export struct integer final : object {
inline static constexpr object_type ucl_type = object_type::integer;
- integer(value_type value)
- : object(::ucl_object_fromint(value))
+ // Create a new integer from a UCL object.
+ integer(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
{
- if (_object == nullptr)
- throw error("failed to create UCL object");
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
}
- explicit integer(::ucl_object_t *uobj) : object(uobj)
+ integer(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
{
- assert(type() == object_type::integer);
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+ }
+
+ // Create a new integer from a value.
+ integer(value_type value)
+ : object(noref, ::ucl_object_fromint(value))
+ {
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
}
+ // Return the value of this object.
auto value(this integer const &self) -> value_type
{
auto v = value_type{};
diff --git a/nihil.ucl/object.ccm b/nihil.ucl/object.ccm
index 7286301..72abc00 100644
--- a/nihil.ucl/object.ccm
+++ b/nihil.ucl/object.ccm
@@ -33,16 +33,30 @@ export struct parser;
* The basic object type.
*/
+// Ref the UCL object when creating an object.
+export inline constexpr struct ref_t {} ref;
+// Don't ref the UCL object.
+export inline constexpr struct noref_t {} noref;
+
export struct object {
inline static constexpr object_type ucl_type = object_type::object;
- // Create an object from an existing ucl_object_t. We assume the
- // object has already been referenced.
- object(::ucl_object_t *object) : _object(object) {}
+ // Create an object from an existing ucl_object_t. The first argument
+ // determines whether we ref the object or not.
+
+ object(ref_t, ::ucl_object_t const *object)
+ : _object(::ucl_object_ref(object))
+ {
+ }
+
+ object(noref_t, ::ucl_object_t *object)
+ : _object(object)
+ {
+ }
// Free our object on destruction.
virtual ~object() {
- if (_object)
+ if (_object != nullptr)
::ucl_object_unref(_object);
}
@@ -70,21 +84,24 @@ export struct object {
-> object &
{
if (&self != &other) {
+ auto *new_uobj = ::ucl_object_copy(other.get_ucl_object());
+ if (new_uobj == nullptr)
+ throw error("failed to copy UCL object");
+
if (self._object != nullptr)
::ucl_object_unref(self._object);
-
- if (other._object != nullptr) {
- self._object = ::ucl_object_copy(other._object);
- if (self._object == nullptr)
- throw error("failed to copy UCL object");
- } else {
- self._object = nullptr;
- }
+ self._object = new_uobj;
}
return self;
}
+ // Increase the refcount of this object.
+ auto ref(this object const &self) -> object
+ {
+ return object(nihil::ucl::ref, self.get_ucl_object());
+ }
+
// Return the type of this object.
auto type(this object const &self) -> object_type
{
@@ -95,11 +112,15 @@ export struct object {
// Return the underlying object.
auto get_ucl_object(this object &self) -> ::ucl_object_t *
{
+ if (self._object == nullptr)
+ throw error("attempt to access empty UCL object");
return self._object;
}
auto get_ucl_object(this object const &self) -> ::ucl_object_t const *
{
+ if (self._object == nullptr)
+ throw error("attempt to access empty UCL object");
return self._object;
}
@@ -107,7 +128,8 @@ export struct object {
auto key(this object const &self) -> std::string_view
{
auto dlen = std::size_t{};
- auto const *dptr = ::ucl_object_keyl(self._object, &dlen);
+ auto const *dptr = ::ucl_object_keyl(self.get_ucl_object(),
+ &dlen);
return {dptr, dlen};
}
@@ -116,11 +138,12 @@ export struct object {
-> std::optional<object>
{
auto const *obj = ::ucl_object_lookup_any(
- self._object, key.data(), key.size());
+ self.get_ucl_object(),
+ key.data(), key.size());
if (obj == nullptr)
return {};
- return {object(::ucl_object_ref(obj))};
+ return {object(nihil::ucl::ref, obj)};
}
protected:
@@ -194,8 +217,7 @@ export struct iterator {
}
auto operator*(this iterator const &self) -> object {
- auto *ptr = ::ucl_object_ref(self._state->cur);
- return object(ptr);
+ return object(ref, self._state->cur);
}
private:
diff --git a/nihil.ucl/object_cast.ccm b/nihil.ucl/object_cast.ccm
index 7291960..b10ffbc 100644
--- a/nihil.ucl/object_cast.ccm
+++ b/nihil.ucl/object_cast.ccm
@@ -71,11 +71,10 @@ struct convert_check<array<T>>
export template<datatype To>
auto object_cast(object const &from) -> To
{
- convert_check<To>{}.check(from.get_ucl_object());
+ auto uobj = from.get_ucl_object();
- auto const *uobj = from.get_ucl_object();
- auto *refptr = ::ucl_object_ref(uobj);
- return To(refptr);
+ convert_check<To>{}.check(uobj);
+ return To(nihil::ucl::ref, uobj);
}
} // namespace nihil::ucl
diff --git a/nihil.ucl/parser.ccm b/nihil.ucl/parser.ccm
index 17ed79c..968e906 100644
--- a/nihil.ucl/parser.ccm
+++ b/nihil.ucl/parser.ccm
@@ -147,7 +147,8 @@ export struct parser {
if (obj == nullptr)
throw error("attempt to call top() on an empty parser");
- return {obj};
+ // ucl_parser_get_objects() refs the object for us.
+ return {noref, obj};
}
private:
diff --git a/nihil.ucl/real.ccm b/nihil.ucl/real.ccm
index 4639109..d968667 100644
--- a/nihil.ucl/real.ccm
+++ b/nihil.ucl/real.ccm
@@ -21,16 +21,27 @@ export struct real final : object {
inline static constexpr object_type ucl_type = object_type::real;
- real(value_type value)
- : object(::ucl_object_fromdouble(value))
+ // Create a new real from a UCL object.
+ real(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
{
- if (_object == nullptr)
- throw error("failed to create UCL object");
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
}
- explicit real(::ucl_object_t *uobj) : object(uobj)
+ real(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
{
- assert(type() == object_type::real);
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+ }
+
+ // Create a new real from a value.
+ real(value_type value)
+ : object(noref, ::ucl_object_fromdouble(value))
+ {
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
}
auto value(this real const &self) -> value_type
diff --git a/nihil.ucl/string.ccm b/nihil.ucl/string.ccm
index e41c70f..ffad847 100644
--- a/nihil.ucl/string.ccm
+++ b/nihil.ucl/string.ccm
@@ -21,19 +21,51 @@ export struct string final : object {
inline static constexpr object_type ucl_type = object_type::string;
- string(value_type value)
- : object(::ucl_object_fromstring_common(
- value.data(), value.size(), UCL_STRING_RAW))
+ // Create a new string from a UCL object.
+ string(ref_t, ::ucl_object_t const *uobj)
+ : object(nihil::ucl::ref, uobj)
{
- if (_object == nullptr)
- throw error("failed to create UCL object");
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
}
- explicit string(::ucl_object_t *uobj) : object(uobj)
+ string(noref_t, ::ucl_object_t *uobj)
+ : object(noref, uobj)
{
- assert(type() == object_type::string);
+ if (type() != ucl_type)
+ throw type_mismatch(ucl_type, type());
+ }
+
+ // Create a new UCL string from a string.
+ string(std::string_view value)
+ : object(nihil::ucl::ref,
+ ::ucl_object_fromstring_common(
+ value.data(), value.size(),
+ UCL_STRING_RAW))
+ {
+ if (_object == nullptr)
+ throw error("failed to create UCL object");
}
+ // 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))
+ {}
+
+ template<std::input_iterator Iterator>
+ requires(!std::contiguous_iterator<Iterator>)
+ string(Iterator first, Iterator last)
+ : string(std::string(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))
+ {}
+
+ // Return the value of this string.
auto value(this string const &self) -> value_type
{
char const *dptr{};
diff --git a/nihil.ucl/tests/array.cc b/nihil.ucl/tests/array.cc
index 220564d..a4f26b6 100644
--- a/nihil.ucl/tests/array.cc
+++ b/nihil.ucl/tests/array.cc
@@ -210,7 +210,7 @@ TEST_CASE("ucl: array: homogeneous cast", "[ucl]")
arr.push_back(integer(1));
arr.push_back(integer(42));
- auto obj = object(arr.get_ucl_object());
+ auto obj = object(ref, arr.get_ucl_object());
// Converting to array<string> should fail.
REQUIRE_THROWS_AS(object_cast<array<string>>(obj), type_mismatch);