[02/11] libcamera: yaml_parser: Delegate YamlObject::get() to helper structure
diff mbox series

Message ID 20240613013944.23344-3-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • ipa: libipa: Vector and Pwl improvements
Related show

Commit Message

Laurent Pinchart June 13, 2024, 1:39 a.m. UTC
The YamlObject::get() function is a function template that gets fully
specialized for various types. This works fine for non-template types,
but specializing it for template types (e.g. a std::vector<U>) would
require partial template specialization, which C++ allows for classes
and variables but not functions.

To work around this problem, delegate the implementation to a new
YamlObject::Getter structure template, which will support partial
specialization.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 include/libcamera/internal/yaml_parser.h | 12 +++-
 src/libcamera/yaml_parser.cpp            | 78 +++++++++++++-----------
 2 files changed, 55 insertions(+), 35 deletions(-)

Comments

Paul Elder June 13, 2024, 7:26 a.m. UTC | #1
On Thu, Jun 13, 2024 at 04:39:35AM +0300, Laurent Pinchart wrote:
> The YamlObject::get() function is a function template that gets fully
> specialized for various types. This works fine for non-template types,
> but specializing it for template types (e.g. a std::vector<U>) would
> require partial template specialization, which C++ allows for classes
> and variables but not functions.
> 
> To work around this problem, delegate the implementation to a new
> YamlObject::Getter structure template, which will support partial
> specialization.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>

> ---
>  include/libcamera/internal/yaml_parser.h | 12 +++-
>  src/libcamera/yaml_parser.cpp            | 78 +++++++++++++-----------
>  2 files changed, 55 insertions(+), 35 deletions(-)
> 
> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h
> index 81cc0e25ae0f..06a41146ad01 100644
> --- a/include/libcamera/internal/yaml_parser.h
> +++ b/include/libcamera/internal/yaml_parser.h
> @@ -162,7 +162,10 @@ public:
>  	std::size_t size() const;
>  
>  	template<typename T>
> -	std::optional<T> get() const;
> +	std::optional<T> get() const
> +	{
> +		return Getter<T>{}.get(*this);
> +	}
>  
>  	template<typename T, typename U>
>  	T get(U &&defaultValue) const
> @@ -199,6 +202,8 @@ public:
>  private:
>  	LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject)
>  
> +	template<typename T>
> +	friend struct Getter;
>  	friend class YamlParserContext;
>  
>  	enum class Type {
> @@ -207,6 +212,11 @@ private:
>  		Value,
>  	};
>  
> +	template<typename T>
> +	struct Getter {
> +		std::optional<T> get(const YamlObject &obj) const;
> +	};
> +
>  	Type type_;
>  
>  	std::string value_;
> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp
> index b68a44c15c35..56670ba7a584 100644
> --- a/src/libcamera/yaml_parser.cpp
> +++ b/src/libcamera/yaml_parser.cpp
> @@ -118,14 +118,15 @@ std::size_t YamlObject::size() const
>  #ifndef __DOXYGEN__
>  
>  template<>
> -std::optional<bool> YamlObject::get() const
> +std::optional<bool>
> +YamlObject::Getter<bool>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
> -	if (value_ == "true")
> +	if (obj.value_ == "true")
>  		return true;
> -	else if (value_ == "false")
> +	else if (obj.value_ == "false")
>  		return false;
>  
>  	return std::nullopt;
> @@ -182,14 +183,15 @@ bool parseUnsignedInteger(const std::string &str, unsigned long max,
>  } /* namespace */
>  
>  template<>
> -std::optional<int8_t> YamlObject::get() const
> +std::optional<int8_t>
> +YamlObject::Getter<int8_t>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
>  	long value;
>  
> -	if (!parseSignedInteger(value_, std::numeric_limits<int8_t>::min(),
> +	if (!parseSignedInteger(obj.value_, std::numeric_limits<int8_t>::min(),
>  				std::numeric_limits<int8_t>::max(), &value))
>  		return std::nullopt;
>  
> @@ -197,14 +199,15 @@ std::optional<int8_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<uint8_t> YamlObject::get() const
> +std::optional<uint8_t>
> +YamlObject::Getter<uint8_t>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
>  	unsigned long value;
>  
> -	if (!parseUnsignedInteger(value_, std::numeric_limits<uint8_t>::max(),
> +	if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint8_t>::max(),
>  				  &value))
>  		return std::nullopt;
>  
> @@ -212,14 +215,15 @@ std::optional<uint8_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<int16_t> YamlObject::get() const
> +std::optional<int16_t>
> +YamlObject::Getter<int16_t>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
>  	long value;
>  
> -	if (!parseSignedInteger(value_, std::numeric_limits<int16_t>::min(),
> +	if (!parseSignedInteger(obj.value_, std::numeric_limits<int16_t>::min(),
>  				std::numeric_limits<int16_t>::max(), &value))
>  		return std::nullopt;
>  
> @@ -227,14 +231,15 @@ std::optional<int16_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<uint16_t> YamlObject::get() const
> +std::optional<uint16_t>
> +YamlObject::Getter<uint16_t>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
>  	unsigned long value;
>  
> -	if (!parseUnsignedInteger(value_, std::numeric_limits<uint16_t>::max(),
> +	if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint16_t>::max(),
>  				  &value))
>  		return std::nullopt;
>  
> @@ -242,14 +247,15 @@ std::optional<uint16_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<int32_t> YamlObject::get() const
> +std::optional<int32_t>
> +YamlObject::Getter<int32_t>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
>  	long value;
>  
> -	if (!parseSignedInteger(value_, std::numeric_limits<int32_t>::min(),
> +	if (!parseSignedInteger(obj.value_, std::numeric_limits<int32_t>::min(),
>  				std::numeric_limits<int32_t>::max(), &value))
>  		return std::nullopt;
>  
> @@ -257,14 +263,15 @@ std::optional<int32_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<uint32_t> YamlObject::get() const
> +std::optional<uint32_t>
> +YamlObject::Getter<uint32_t>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
>  	unsigned long value;
>  
> -	if (!parseUnsignedInteger(value_, std::numeric_limits<uint32_t>::max(),
> +	if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint32_t>::max(),
>  				  &value))
>  		return std::nullopt;
>  
> @@ -272,18 +279,19 @@ std::optional<uint32_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<double> YamlObject::get() const
> +std::optional<double>
> +YamlObject::Getter<double>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
> -	if (value_ == "")
> +	if (obj.value_ == "")
>  		return std::nullopt;
>  
>  	char *end;
>  
>  	errno = 0;
> -	double value = utils::strtod(value_.c_str(), &end);
> +	double value = utils::strtod(obj.value_.c_str(), &end);
>  
>  	if ('\0' != *end || errno == ERANGE)
>  		return std::nullopt;
> @@ -292,28 +300,30 @@ std::optional<double> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<std::string> YamlObject::get() const
> +std::optional<std::string>
> +YamlObject::Getter<std::string>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::Value)
> +	if (obj.type_ != Type::Value)
>  		return std::nullopt;
>  
> -	return value_;
> +	return obj.value_;
>  }
>  
>  template<>
> -std::optional<Size> YamlObject::get() const
> +std::optional<Size>
> +YamlObject::Getter<Size>::get(const YamlObject &obj) const
>  {
> -	if (type_ != Type::List)
> +	if (obj.type_ != Type::List)
>  		return std::nullopt;
>  
> -	if (list_.size() != 2)
> +	if (obj.list_.size() != 2)
>  		return std::nullopt;
>  
> -	auto width = list_[0].value->get<uint32_t>();
> +	auto width = obj.list_[0].value->get<uint32_t>();
>  	if (!width)
>  		return std::nullopt;
>  
> -	auto height = list_[1].value->get<uint32_t>();
> +	auto height = obj.list_[1].value->get<uint32_t>();
>  	if (!height)
>  		return std::nullopt;
>
Kieran Bingham June 13, 2024, 11:38 a.m. UTC | #2
Quoting Laurent Pinchart (2024-06-13 02:39:35)
> The YamlObject::get() function is a function template that gets fully
> specialized for various types. This works fine for non-template types,
> but specializing it for template types (e.g. a std::vector<U>) would
> require partial template specialization, which C++ allows for classes
> and variables but not functions.
> 
> To work around this problem, delegate the implementation to a new
> YamlObject::Getter structure template, which will support partial
> specialization.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  include/libcamera/internal/yaml_parser.h | 12 +++-
>  src/libcamera/yaml_parser.cpp            | 78 +++++++++++++-----------
>  2 files changed, 55 insertions(+), 35 deletions(-)
> 
> diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h
> index 81cc0e25ae0f..06a41146ad01 100644
> --- a/include/libcamera/internal/yaml_parser.h
> +++ b/include/libcamera/internal/yaml_parser.h
> @@ -162,7 +162,10 @@ public:
>         std::size_t size() const;
>  
>         template<typename T>
> -       std::optional<T> get() const;
> +       std::optional<T> get() const
> +       {
> +               return Getter<T>{}.get(*this);
> +       }

Aha, this is the magic I missed on my first pass. I was curious how we
were changing all these fucntions to now need an object, and I couldn't
see core changes not passing it in - but it comes from here.

Ok so that's neat - and means nothing else is impacted during the
transition...

It all falls into place:

Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

>  
>         template<typename T, typename U>
>         T get(U &&defaultValue) const
> @@ -199,6 +202,8 @@ public:
>  private:
>         LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject)
>  
> +       template<typename T>
> +       friend struct Getter;
>         friend class YamlParserContext;
>  
>         enum class Type {
> @@ -207,6 +212,11 @@ private:
>                 Value,
>         };
>  
> +       template<typename T>
> +       struct Getter {
> +               std::optional<T> get(const YamlObject &obj) const;
> +       };
> +
>         Type type_;
>  
>         std::string value_;
> diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp
> index b68a44c15c35..56670ba7a584 100644
> --- a/src/libcamera/yaml_parser.cpp
> +++ b/src/libcamera/yaml_parser.cpp
> @@ -118,14 +118,15 @@ std::size_t YamlObject::size() const
>  #ifndef __DOXYGEN__
>  
>  template<>
> -std::optional<bool> YamlObject::get() const
> +std::optional<bool>
> +YamlObject::Getter<bool>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
> -       if (value_ == "true")
> +       if (obj.value_ == "true")
>                 return true;
> -       else if (value_ == "false")
> +       else if (obj.value_ == "false")
>                 return false;
>  
>         return std::nullopt;
> @@ -182,14 +183,15 @@ bool parseUnsignedInteger(const std::string &str, unsigned long max,
>  } /* namespace */
>  
>  template<>
> -std::optional<int8_t> YamlObject::get() const
> +std::optional<int8_t>
> +YamlObject::Getter<int8_t>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
>         long value;
>  
> -       if (!parseSignedInteger(value_, std::numeric_limits<int8_t>::min(),
> +       if (!parseSignedInteger(obj.value_, std::numeric_limits<int8_t>::min(),
>                                 std::numeric_limits<int8_t>::max(), &value))
>                 return std::nullopt;
>  
> @@ -197,14 +199,15 @@ std::optional<int8_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<uint8_t> YamlObject::get() const
> +std::optional<uint8_t>
> +YamlObject::Getter<uint8_t>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
>         unsigned long value;
>  
> -       if (!parseUnsignedInteger(value_, std::numeric_limits<uint8_t>::max(),
> +       if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint8_t>::max(),
>                                   &value))
>                 return std::nullopt;
>  
> @@ -212,14 +215,15 @@ std::optional<uint8_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<int16_t> YamlObject::get() const
> +std::optional<int16_t>
> +YamlObject::Getter<int16_t>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
>         long value;
>  
> -       if (!parseSignedInteger(value_, std::numeric_limits<int16_t>::min(),
> +       if (!parseSignedInteger(obj.value_, std::numeric_limits<int16_t>::min(),
>                                 std::numeric_limits<int16_t>::max(), &value))
>                 return std::nullopt;
>  
> @@ -227,14 +231,15 @@ std::optional<int16_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<uint16_t> YamlObject::get() const
> +std::optional<uint16_t>
> +YamlObject::Getter<uint16_t>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
>         unsigned long value;
>  
> -       if (!parseUnsignedInteger(value_, std::numeric_limits<uint16_t>::max(),
> +       if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint16_t>::max(),
>                                   &value))
>                 return std::nullopt;
>  
> @@ -242,14 +247,15 @@ std::optional<uint16_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<int32_t> YamlObject::get() const
> +std::optional<int32_t>
> +YamlObject::Getter<int32_t>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
>         long value;
>  
> -       if (!parseSignedInteger(value_, std::numeric_limits<int32_t>::min(),
> +       if (!parseSignedInteger(obj.value_, std::numeric_limits<int32_t>::min(),
>                                 std::numeric_limits<int32_t>::max(), &value))
>                 return std::nullopt;
>  
> @@ -257,14 +263,15 @@ std::optional<int32_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<uint32_t> YamlObject::get() const
> +std::optional<uint32_t>
> +YamlObject::Getter<uint32_t>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
>         unsigned long value;
>  
> -       if (!parseUnsignedInteger(value_, std::numeric_limits<uint32_t>::max(),
> +       if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint32_t>::max(),
>                                   &value))
>                 return std::nullopt;
>  
> @@ -272,18 +279,19 @@ std::optional<uint32_t> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<double> YamlObject::get() const
> +std::optional<double>
> +YamlObject::Getter<double>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
> -       if (value_ == "")
> +       if (obj.value_ == "")
>                 return std::nullopt;
>  
>         char *end;
>  
>         errno = 0;
> -       double value = utils::strtod(value_.c_str(), &end);
> +       double value = utils::strtod(obj.value_.c_str(), &end);
>  
>         if ('\0' != *end || errno == ERANGE)
>                 return std::nullopt;
> @@ -292,28 +300,30 @@ std::optional<double> YamlObject::get() const
>  }
>  
>  template<>
> -std::optional<std::string> YamlObject::get() const
> +std::optional<std::string>
> +YamlObject::Getter<std::string>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::Value)
> +       if (obj.type_ != Type::Value)
>                 return std::nullopt;
>  
> -       return value_;
> +       return obj.value_;
>  }
>  
>  template<>
> -std::optional<Size> YamlObject::get() const
> +std::optional<Size>
> +YamlObject::Getter<Size>::get(const YamlObject &obj) const
>  {
> -       if (type_ != Type::List)
> +       if (obj.type_ != Type::List)
>                 return std::nullopt;
>  
> -       if (list_.size() != 2)
> +       if (obj.list_.size() != 2)
>                 return std::nullopt;
>  
> -       auto width = list_[0].value->get<uint32_t>();
> +       auto width = obj.list_[0].value->get<uint32_t>();
>         if (!width)
>                 return std::nullopt;
>  
> -       auto height = list_[1].value->get<uint32_t>();
> +       auto height = obj.list_[1].value->get<uint32_t>();
>         if (!height)
>                 return std::nullopt;
>  
> -- 
> Regards,
> 
> Laurent Pinchart
>

Patch
diff mbox series

diff --git a/include/libcamera/internal/yaml_parser.h b/include/libcamera/internal/yaml_parser.h
index 81cc0e25ae0f..06a41146ad01 100644
--- a/include/libcamera/internal/yaml_parser.h
+++ b/include/libcamera/internal/yaml_parser.h
@@ -162,7 +162,10 @@  public:
 	std::size_t size() const;
 
 	template<typename T>
-	std::optional<T> get() const;
+	std::optional<T> get() const
+	{
+		return Getter<T>{}.get(*this);
+	}
 
 	template<typename T, typename U>
 	T get(U &&defaultValue) const
@@ -199,6 +202,8 @@  public:
 private:
 	LIBCAMERA_DISABLE_COPY_AND_MOVE(YamlObject)
 
+	template<typename T>
+	friend struct Getter;
 	friend class YamlParserContext;
 
 	enum class Type {
@@ -207,6 +212,11 @@  private:
 		Value,
 	};
 
+	template<typename T>
+	struct Getter {
+		std::optional<T> get(const YamlObject &obj) const;
+	};
+
 	Type type_;
 
 	std::string value_;
diff --git a/src/libcamera/yaml_parser.cpp b/src/libcamera/yaml_parser.cpp
index b68a44c15c35..56670ba7a584 100644
--- a/src/libcamera/yaml_parser.cpp
+++ b/src/libcamera/yaml_parser.cpp
@@ -118,14 +118,15 @@  std::size_t YamlObject::size() const
 #ifndef __DOXYGEN__
 
 template<>
-std::optional<bool> YamlObject::get() const
+std::optional<bool>
+YamlObject::Getter<bool>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
-	if (value_ == "true")
+	if (obj.value_ == "true")
 		return true;
-	else if (value_ == "false")
+	else if (obj.value_ == "false")
 		return false;
 
 	return std::nullopt;
@@ -182,14 +183,15 @@  bool parseUnsignedInteger(const std::string &str, unsigned long max,
 } /* namespace */
 
 template<>
-std::optional<int8_t> YamlObject::get() const
+std::optional<int8_t>
+YamlObject::Getter<int8_t>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
 	long value;
 
-	if (!parseSignedInteger(value_, std::numeric_limits<int8_t>::min(),
+	if (!parseSignedInteger(obj.value_, std::numeric_limits<int8_t>::min(),
 				std::numeric_limits<int8_t>::max(), &value))
 		return std::nullopt;
 
@@ -197,14 +199,15 @@  std::optional<int8_t> YamlObject::get() const
 }
 
 template<>
-std::optional<uint8_t> YamlObject::get() const
+std::optional<uint8_t>
+YamlObject::Getter<uint8_t>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
 	unsigned long value;
 
-	if (!parseUnsignedInteger(value_, std::numeric_limits<uint8_t>::max(),
+	if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint8_t>::max(),
 				  &value))
 		return std::nullopt;
 
@@ -212,14 +215,15 @@  std::optional<uint8_t> YamlObject::get() const
 }
 
 template<>
-std::optional<int16_t> YamlObject::get() const
+std::optional<int16_t>
+YamlObject::Getter<int16_t>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
 	long value;
 
-	if (!parseSignedInteger(value_, std::numeric_limits<int16_t>::min(),
+	if (!parseSignedInteger(obj.value_, std::numeric_limits<int16_t>::min(),
 				std::numeric_limits<int16_t>::max(), &value))
 		return std::nullopt;
 
@@ -227,14 +231,15 @@  std::optional<int16_t> YamlObject::get() const
 }
 
 template<>
-std::optional<uint16_t> YamlObject::get() const
+std::optional<uint16_t>
+YamlObject::Getter<uint16_t>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
 	unsigned long value;
 
-	if (!parseUnsignedInteger(value_, std::numeric_limits<uint16_t>::max(),
+	if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint16_t>::max(),
 				  &value))
 		return std::nullopt;
 
@@ -242,14 +247,15 @@  std::optional<uint16_t> YamlObject::get() const
 }
 
 template<>
-std::optional<int32_t> YamlObject::get() const
+std::optional<int32_t>
+YamlObject::Getter<int32_t>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
 	long value;
 
-	if (!parseSignedInteger(value_, std::numeric_limits<int32_t>::min(),
+	if (!parseSignedInteger(obj.value_, std::numeric_limits<int32_t>::min(),
 				std::numeric_limits<int32_t>::max(), &value))
 		return std::nullopt;
 
@@ -257,14 +263,15 @@  std::optional<int32_t> YamlObject::get() const
 }
 
 template<>
-std::optional<uint32_t> YamlObject::get() const
+std::optional<uint32_t>
+YamlObject::Getter<uint32_t>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
 	unsigned long value;
 
-	if (!parseUnsignedInteger(value_, std::numeric_limits<uint32_t>::max(),
+	if (!parseUnsignedInteger(obj.value_, std::numeric_limits<uint32_t>::max(),
 				  &value))
 		return std::nullopt;
 
@@ -272,18 +279,19 @@  std::optional<uint32_t> YamlObject::get() const
 }
 
 template<>
-std::optional<double> YamlObject::get() const
+std::optional<double>
+YamlObject::Getter<double>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
-	if (value_ == "")
+	if (obj.value_ == "")
 		return std::nullopt;
 
 	char *end;
 
 	errno = 0;
-	double value = utils::strtod(value_.c_str(), &end);
+	double value = utils::strtod(obj.value_.c_str(), &end);
 
 	if ('\0' != *end || errno == ERANGE)
 		return std::nullopt;
@@ -292,28 +300,30 @@  std::optional<double> YamlObject::get() const
 }
 
 template<>
-std::optional<std::string> YamlObject::get() const
+std::optional<std::string>
+YamlObject::Getter<std::string>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::Value)
+	if (obj.type_ != Type::Value)
 		return std::nullopt;
 
-	return value_;
+	return obj.value_;
 }
 
 template<>
-std::optional<Size> YamlObject::get() const
+std::optional<Size>
+YamlObject::Getter<Size>::get(const YamlObject &obj) const
 {
-	if (type_ != Type::List)
+	if (obj.type_ != Type::List)
 		return std::nullopt;
 
-	if (list_.size() != 2)
+	if (obj.list_.size() != 2)
 		return std::nullopt;
 
-	auto width = list_[0].value->get<uint32_t>();
+	auto width = obj.list_[0].value->get<uint32_t>();
 	if (!width)
 		return std::nullopt;
 
-	auto height = list_[1].value->get<uint32_t>();
+	auto height = obj.list_[1].value->get<uint32_t>();
 	if (!height)
 		return std::nullopt;