diff mbox series

[libgpiod,v2,v6,2/5] bindings: cxx: add v2 headers

Message ID 20220426125023.2664623-3-brgl@bgdev.pl
State New
Headers show
Series bindings: cxx: implement C++ bindings for libgpiod v2.0 | expand

Commit Message

Bartosz Golaszewski April 26, 2022, 12:50 p.m. UTC
This adds the headers for the v2 C++ bindings.

Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
 Doxyfile.in                                 |   4 +-
 bindings/cxx/gpiodcxx/Makefile.am           |  18 +
 bindings/cxx/gpiodcxx/chip-info.hpp         | 105 ++++
 bindings/cxx/gpiodcxx/chip.hpp              | 179 +++++++
 bindings/cxx/gpiodcxx/edge-event-buffer.hpp | 129 +++++
 bindings/cxx/gpiodcxx/edge-event.hpp        | 137 +++++
 bindings/cxx/gpiodcxx/exception.hpp         | 158 ++++++
 bindings/cxx/gpiodcxx/info-event.hpp        | 123 +++++
 bindings/cxx/gpiodcxx/line-config.hpp       | 564 ++++++++++++++++++++
 bindings/cxx/gpiodcxx/line-info.hpp         | 176 ++++++
 bindings/cxx/gpiodcxx/line-request.hpp      | 221 ++++++++
 bindings/cxx/gpiodcxx/line.hpp              | 274 ++++++++++
 bindings/cxx/gpiodcxx/misc.hpp              |  44 ++
 bindings/cxx/gpiodcxx/request-config.hpp    | 163 ++++++
 bindings/cxx/gpiodcxx/timestamp.hpp         | 122 +++++
 configure.ac                                |   1 +
 16 files changed, 2417 insertions(+), 1 deletion(-)
 create mode 100644 bindings/cxx/gpiodcxx/Makefile.am
 create mode 100644 bindings/cxx/gpiodcxx/chip-info.hpp
 create mode 100644 bindings/cxx/gpiodcxx/chip.hpp
 create mode 100644 bindings/cxx/gpiodcxx/edge-event-buffer.hpp
 create mode 100644 bindings/cxx/gpiodcxx/edge-event.hpp
 create mode 100644 bindings/cxx/gpiodcxx/exception.hpp
 create mode 100644 bindings/cxx/gpiodcxx/info-event.hpp
 create mode 100644 bindings/cxx/gpiodcxx/line-config.hpp
 create mode 100644 bindings/cxx/gpiodcxx/line-info.hpp
 create mode 100644 bindings/cxx/gpiodcxx/line-request.hpp
 create mode 100644 bindings/cxx/gpiodcxx/line.hpp
 create mode 100644 bindings/cxx/gpiodcxx/misc.hpp
 create mode 100644 bindings/cxx/gpiodcxx/request-config.hpp
 create mode 100644 bindings/cxx/gpiodcxx/timestamp.hpp

Comments

Bartosz Golaszewski May 5, 2022, 8:20 a.m. UTC | #1
On Tue, Apr 26, 2022 at 2:50 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> This adds the headers for the v2 C++ bindings.
>
> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>

I'm pasting below the review I got from my work colleague Bernhard
Rosenkränzer (Cc'ed):

Bart

---

Looks good to me, one minor nit: I presume bindings/cxx/gpiod.hpp Is
supposed to be #include-d by users of the library. The definition of
GPIOD_CXX_API in the file causes the symbol to be re-exported by
anything including the header. Usually the way to achieve what you
want there is

AM_CPPFLAGS += -DBUILDING_GPIOD=1
in Makefile.am, and the definition of GPIOD_CXX_API changed to

#ifdef BUILDING_GPIOD
#define GPIOD_CXX_API __attribute__((visibility("default")))
#else
#define GPIOD_CXX_API __attribute__((visibility("hidden")))
#endif

Also, in Makefile.am you probably want to change
libgpiodcxx_la_CPPFLAGS to libgpiodcxx_la_CXXFLAGS -- CPPFLAGS is for
C/C++ PreProcessor flags, CXXFLAGS is for the C++ compiler

Doesn't make much of a difference currently because at least with
clang and gcc the preprocessor isn't called separately, but you never
know what kind of insanity a future automake version will bring

You might also want to change the various methods taking (void) [none]
as parameters to just taking () -- (void) is a C-ism, not needed for
C++ (and you never know if at some point the standard will actually
disallow it)

Also, I'm not sure if it's intentional that some classes (class chip
etc.) aren't marked GPIOD_CXX_API

line-config.hpp uses using override = ::std::pair<line::offset,
property>; -- override is a reserved word (to be used by something
inheriting a class to indicate the method being defined overrides a
base class method -- optional, what it actually does is cause a
compile time error if parameters mismatch or there's some other reason
why it doesn't overload something), so using it in this context might
break with some compilers

Minor nit: some parameters could add more const-ness (e.g. void
clear_drive_override(*const* line::offset offset) noexcept;)

In theory, this could help a compiler optimize something out, but in
practice I don't know any compiler that would actually generate better
code from that
diff mbox series

Patch

diff --git a/Doxyfile.in b/Doxyfile.in
index 0ff735d..9c85e21 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -44,7 +44,9 @@  WARNINGS               = YES
 WARN_IF_UNDOCUMENTED   = YES
 WARN_FORMAT            =
 WARN_LOGFILE           =
-INPUT                  = @top_srcdir@/include/gpiod.h @top_srcdir@/bindings/cxx/gpiod.hpp
+INPUT                  = @top_srcdir@/include/gpiod.h \
+                         @top_srcdir@/bindings/cxx/gpiod.hpp \
+                         @top_srcdir@/bindings/cxx/gpiodcxx/
 SOURCE_BROWSER         = YES
 INLINE_SOURCES         = NO
 REFERENCED_BY_RELATION = YES
diff --git a/bindings/cxx/gpiodcxx/Makefile.am b/bindings/cxx/gpiodcxx/Makefile.am
new file mode 100644
index 0000000..71532e6
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/Makefile.am
@@ -0,0 +1,18 @@ 
+# SPDX-License-Identifier: GPL-2.0-or-later
+# SPDX-FileCopyrightText: 2021 Bartosz Golaszewski <brgl@bgdev.pl>
+
+otherincludedir = $(includedir)/gpiodcxx
+otherinclude_HEADERS = \
+	chip.hpp \
+	chip-info.hpp \
+	edge-event-buffer.hpp \
+	edge-event.hpp \
+	exception.hpp \
+	info-event.hpp \
+	line.hpp \
+	line-config.hpp \
+	line-info.hpp \
+	line-request.hpp \
+	misc.hpp \
+	request-config.hpp \
+	timestamp.hpp
diff --git a/bindings/cxx/gpiodcxx/chip-info.hpp b/bindings/cxx/gpiodcxx/chip-info.hpp
new file mode 100644
index 0000000..9313e88
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/chip-info.hpp
@@ -0,0 +1,105 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file chip-info.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_CHIP_INFO_HPP__
+#define __LIBGPIOD_CXX_CHIP_INFO_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <memory>
+#include <ostream>
+
+namespace gpiod {
+
+class chip;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Represents an immutable snapshot of GPIO chip information.
+ */
+class chip_info
+{
+public:
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy.
+	 */
+	chip_info(const chip_info& other);
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	chip_info(chip_info&& other) noexcept;
+
+	~chip_info(void);
+
+	/**
+	 * @brief Assignment operator.
+	 * @param other Object to copy.
+	 * @return Reference to self.
+	 */
+	chip_info& operator=(const chip_info& other);
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	chip_info& operator=(chip_info&& other) noexcept;
+
+	/**
+	 * @brief Get the name of this GPIO chip.
+	 * @return String containing the chip name.
+	 */
+	::std::string name(void) const noexcept;
+
+	/**
+	 * @brief Get the label of this GPIO chip.
+	 * @return String containing the chip name.
+	 */
+	::std::string label(void) const noexcept;
+
+	/**
+	 * @brief Return the number of lines exposed by this chip.
+	 * @return Number of lines.
+	 */
+	::std::size_t num_lines(void) const noexcept;
+
+private:
+
+	chip_info(void);
+
+	struct impl;
+
+	::std::shared_ptr<impl> _m_priv;
+
+	friend chip;
+};
+
+/**
+ * @brief Stream insertion operator for GPIO chip objects.
+ * @param out Output stream to write to.
+ * @param chip GPIO chip to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const chip_info& chip);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_CHIP_INFO_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/chip.hpp b/bindings/cxx/gpiodcxx/chip.hpp
new file mode 100644
index 0000000..eae7ed6
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/chip.hpp
@@ -0,0 +1,179 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file chip.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_CHIP_HPP__
+#define __LIBGPIOD_CXX_CHIP_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <chrono>
+#include <cstddef>
+#include <iostream>
+#include <filesystem>
+#include <memory>
+
+#include "line.hpp"
+
+namespace gpiod {
+
+class chip_info;
+class info_event;
+class line_config;
+class line_info;
+class line_request;
+class request_config;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Represents a GPIO chip.
+ */
+class chip
+{
+public:
+
+	/**
+	 * @brief Instantiates a new chip object by opening the device file
+	 *        indicated by the path argument.
+	 * @param path Path to the device file to open.
+	 */
+	explicit chip(const ::std::filesystem::path& path);
+
+	chip(const chip& other) = delete;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	chip(chip&& other) noexcept;
+
+	~chip(void);
+
+	chip& operator=(const chip& other) = delete;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	chip& operator=(chip&& other) noexcept;
+
+	/**
+	 * @brief Check if this object is valid.
+	 * @return True if this object's methods can be used, false otherwise.
+	 *         False usually means the chip was closed. If the user calls
+	 *         any of the methods of this class on an object for which this
+	 *         operator returned false, a logic_error will be thrown.
+	 */
+	explicit operator bool(void) const noexcept;
+
+	/**
+	 * @brief Close the GPIO chip device file and free associated resources.
+	 * @note The chip object can live after calling this method but any of
+	 *       the chip's mutators will throw a logic_error exception.
+	 */
+	void close(void);
+
+	/**
+	 * @brief Get the filesystem path that was used to open this GPIO chip.
+	 * @return Path to the underlying character device file.
+	 */
+	::std::filesystem::path path(void) const;
+
+	/**
+	 * @brief Get information about the chip.
+	 * @return New chip_info object.
+	 */
+	chip_info get_info(void) const;
+
+	/**
+	 * @brief Retrieve the current snapshot of line information for a
+	 *        single line.
+	 * @param offset Offset of the line to get the info for.
+	 * @return New ::gpiod::line_info object.
+	 */
+	line_info get_line_info(line::offset offset) const;
+
+	/**
+	 * @brief Wrapper around ::gpiod::chip::get_line_info that retrieves
+	 *        the line info and starts watching the line for changes.
+	 * @param offset Offset of the line to get the info for.
+	 * @return New ::gpiod::line_info object.
+	 */
+	line_info watch_line_info(line::offset offset) const;
+
+	/**
+	 * @brief Stop watching the line at given offset for info events.
+	 * @param offset Offset of the line to get the info for.
+	 */
+	void unwatch_line_info(line::offset offset) const;
+
+	/**
+	 * @brief Get the file descriptor associated with this chip.
+	 * @return File descriptor number.
+	 */
+	int fd(void) const;
+
+	/**
+	 * @brief Wait for line status events on any of the watched lines
+	 *        exposed by this chip.
+	 * @param timeout Wait time limit in nanoseconds.
+	 * @return True if at least one event is ready to be read. False if the
+	 *         wait timed out.
+	 */
+	bool wait_info_event(const ::std::chrono::nanoseconds& timeout) const;
+
+	/**
+	 * @brief Read a single line status change event from this chip.
+	 * @return New info_event object.
+	 */
+	info_event read_info_event(void) const;
+
+	/**
+	 * @brief Map a GPIO line's name to its offset within the chip.
+	 * @param name Name of the GPIO line to map.
+	 * @return Offset of the line within the chip or -1 if the line with
+	 *         given name is not exposed by this chip.
+	 */
+	int get_line_offset_from_name(const ::std::string& name) const;
+
+	/**
+	 * @brief Request a set of lines for exclusive usage.
+	 * @param req_cfg Request config object.
+	 * @param line_cfg Line config object.
+	 * @return New line_request object.
+	 */
+	line_request request_lines(const request_config& req_cfg,
+				   const line_config& line_cfg);
+
+private:
+
+	struct impl;
+
+	::std::unique_ptr<impl> _m_priv;
+};
+
+/**
+ * @brief Stream insertion operator for GPIO chip objects.
+ * @param out Output stream to write to.
+ * @param chip GPIO chip to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const chip& chip);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_CHIP_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/edge-event-buffer.hpp b/bindings/cxx/gpiodcxx/edge-event-buffer.hpp
new file mode 100644
index 0000000..37ac4f5
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/edge-event-buffer.hpp
@@ -0,0 +1,129 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file edge-event-buffer.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_EDGE_EVENT_BUFFER_HPP__
+#define __LIBGPIOD_CXX_EDGE_EVENT_BUFFER_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <cstddef>
+#include <iostream>
+#include <memory>
+#include <vector>
+
+namespace gpiod {
+
+class edge_event;
+class line_request;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Object into which edge events are read for better performance.
+ *
+ * The edge_event_buffer allows reading edge_event objects into an existing
+ * buffer which improves the performance by avoiding needless memory
+ * allocations.
+ */
+class edge_event_buffer
+{
+public:
+
+	/**
+	 * @brief Constant iterator for iterating over edge events stored in
+	 *        the buffer.
+	 */
+	using const_iterator = ::std::vector<edge_event>::const_iterator;
+
+	/**
+	 * @brief Constructor. Creates a new edge event buffer with given
+	 *        capacity.
+	 * @param capacity Capacity of the new buffer.
+	 */
+	explicit edge_event_buffer(::std::size_t capacity = 64);
+
+	edge_event_buffer(const edge_event_buffer& other) = delete;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	edge_event_buffer(edge_event_buffer&& other) noexcept;
+
+	~edge_event_buffer(void);
+
+	edge_event_buffer& operator=(const edge_event_buffer& other) = delete;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	edge_event_buffer& operator=(edge_event_buffer&& other) noexcept;
+
+	/**
+	 * @brief Get the constant reference to the edge event at given index.
+	 * @param index Index of the event in the buffer.
+	 * @return Constant reference to the edge event.
+	 */
+	const edge_event& get_event(unsigned int index) const;
+
+	/**
+	 * @brief Get the number of edge events currently stored in the buffer.
+	 * @return Number of edge events in the buffer.
+	 */
+	::std::size_t num_events(void) const;
+
+	/**
+	 * @brief Maximum capacity of the buffer.
+	 * @return Buffer capacity.
+	 */
+	::std::size_t capacity(void) const noexcept;
+
+	/**
+	 * @brief Get a constant iterator to the first edge event currently
+	 *        stored in the buffer.
+	 * @return Constant iterator to the first element.
+	 */
+	const_iterator begin(void) const noexcept;
+
+	/**
+	 * @brief Get a constant iterator to the element after the last edge
+	 *        event in the buffer.
+	 * @return Constant iterator to the element after the last edge event.
+	 */
+	const_iterator end(void) const noexcept;
+
+private:
+
+	struct impl;
+
+	::std::unique_ptr<impl> _m_priv;
+
+	friend line_request;
+};
+
+/**
+ * @brief Stream insertion operator for GPIO edge event buffer objects.
+ * @param out Output stream to write to.
+ * @param buf GPIO edge event buffer object to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const edge_event_buffer& buf);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_EDGE_EVENT_BUFFER_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/edge-event.hpp b/bindings/cxx/gpiodcxx/edge-event.hpp
new file mode 100644
index 0000000..0623880
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/edge-event.hpp
@@ -0,0 +1,137 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file edge-event.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_EDGE_EVENT_HPP__
+#define __LIBGPIOD_CXX_EDGE_EVENT_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <cstdint>
+#include <iostream>
+#include <memory>
+
+#include "timestamp.hpp"
+
+namespace gpiod {
+
+class edge_event_buffer;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Immutable object containing data about a single edge event.
+ */
+class edge_event
+{
+public:
+
+	/**
+	 * @brief Edge event types.
+	 */
+	enum class event_type
+	{
+		RISING_EDGE = 1,
+		/**< This is a rising edge event. */
+		FALLING_EDGE
+		/**< This is falling edge event. */
+	};
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy.
+	 */
+	edge_event(const edge_event& other);
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	edge_event(edge_event&& other) noexcept;
+
+	~edge_event(void);
+
+	/**
+	 * @brief Copy assignment operator.
+	 * @param other Object to copy.
+	 * @return Reference to self.
+	 */
+	edge_event& operator=(const edge_event& other);
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	edge_event& operator=(edge_event&& other) noexcept;
+
+	/**
+	 * @brief Retrieve the event type.
+	 * @return Event type (rising or falling edge).
+	 */
+	event_type type(void) const;
+
+	/**
+	 * @brief Retrieve the event time-stamp.
+	 * @return Time-stamp in nanoseconds as registered by the kernel using
+	 *         the configured edge event clock.
+	 */
+	timestamp timestamp_ns(void) const noexcept;
+
+	/**
+	 * @brief Read the offset of the line on which this event was
+	 *        registered.
+	 * @return Line offset.
+	 */
+	line::offset line_offset(void) const noexcept;
+
+	/**
+	 * @brief Get the global sequence number of this event.
+	 * @return Sequence number of the event relative to all lines in the
+	 *         associated line request.
+	 */
+	unsigned long global_seqno(void) const noexcept;
+
+	/**
+	 * @brief Get the event sequence number specific to the concerned line.
+	 * @return Sequence number of the event relative to this line within
+	 *         the lifetime of the associated line request.
+	 */
+	unsigned long line_seqno(void) const noexcept;
+
+private:
+
+	edge_event(void);
+
+	struct impl;
+	struct impl_managed;
+	struct impl_external;
+
+	::std::shared_ptr<impl> _m_priv;
+
+	friend edge_event_buffer;
+};
+
+/**
+ * @brief Stream insertion operator for edge events.
+ * @param out Output stream to write to.
+ * @param event Edge event to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const edge_event& event);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_EDGE_EVENT_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/exception.hpp b/bindings/cxx/gpiodcxx/exception.hpp
new file mode 100644
index 0000000..f4d525b
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/exception.hpp
@@ -0,0 +1,158 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file exception.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_EXCEPTION_HPP__
+#define __LIBGPIOD_CXX_EXCEPTION_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <stdexcept>
+#include <string>
+
+namespace gpiod {
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Exception thrown when an already closed chip is used.
+ */
+class GPIOD_CXX_API chip_closed : public ::std::logic_error
+{
+public:
+
+	/**
+	 * @brief Constructor.
+	 * @param what Human readable reason for error.
+	 */
+	explicit chip_closed(const ::std::string& what);
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy from.
+	 */
+	chip_closed(const chip_closed& other) noexcept;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	chip_closed(chip_closed&& other) noexcept;
+
+	/**
+	 * @brief Assignment operator.
+	 * @param other Object to copy from.
+	 * @return Reference to self.
+	 */
+	chip_closed& operator=(const chip_closed& other) noexcept;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	chip_closed& operator=(chip_closed&& other) noexcept;
+
+	virtual ~chip_closed(void);
+};
+
+/**
+ * @brief Exception thrown when an already released line request is used.
+ */
+class GPIOD_CXX_API request_released : public ::std::logic_error
+{
+public:
+
+	/**
+	 * @brief Constructor.
+	 * @param what Human readable reason for error.
+	 */
+	explicit request_released(const ::std::string& what);
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy from.
+	 */
+	request_released(const request_released& other) noexcept;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	request_released(request_released&& other) noexcept;
+
+	/**
+	 * @brief Assignment operator.
+	 * @param other Object to copy from.
+	 * @return Reference to self.
+	 */
+	request_released& operator=(const request_released& other) noexcept;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	request_released& operator=(request_released&& other) noexcept;
+
+	virtual ~request_released(void);
+};
+
+/**
+ * @brief Exception thrown when the core C library returns an invalid value
+ *        for any of the line_info properties.
+ */
+class GPIOD_CXX_API bad_mapping : public ::std::runtime_error
+{
+public:
+
+	/**
+	 * @brief Constructor.
+	 * @param what Human readable reason for error.
+	 */
+	explicit bad_mapping(const ::std::string& what);
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy from.
+	 */
+	bad_mapping(const bad_mapping& other) noexcept;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	bad_mapping(bad_mapping&& other) noexcept;
+
+	/**
+	 * @brief Assignment operator.
+	 * @param other Object to copy from.
+	 * @return Reference to self.
+	 */
+	bad_mapping& operator=(const bad_mapping& other) noexcept;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	bad_mapping& operator=(bad_mapping&& other) noexcept;
+
+	virtual ~bad_mapping(void);
+};
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_EXCEPTION_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/info-event.hpp b/bindings/cxx/gpiodcxx/info-event.hpp
new file mode 100644
index 0000000..107ca57
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/info-event.hpp
@@ -0,0 +1,123 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file gpiod.h
+ */
+
+#ifndef __LIBGPIOD_CXX_INFO_EVENT_HPP__
+#define __LIBGPIOD_CXX_INFO_EVENT_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <cstdint>
+#include <iostream>
+#include <memory>
+
+#include "timestamp.hpp"
+
+namespace gpiod {
+
+class chip;
+class line_info;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Immutable object containing data about a single line info event.
+ */
+class info_event
+{
+public:
+
+	/**
+	 * @brief Types of info events.
+	 */
+	enum class event_type
+	{
+		LINE_REQUESTED = 1,
+		/**< Line has been requested. */
+		LINE_RELEASED,
+		/**< Previously requested line has been released. */
+		LINE_CONFIG_CHANGED
+		/**< Line configuration has changed. */
+	};
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy.
+	 */
+	info_event(const info_event& other);
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	info_event(info_event&& other) noexcept;
+
+	~info_event(void);
+
+	/**
+	 * @brief Copy assignment operator.
+	 * @param other Object to copy.
+	 * @return Reference to self.
+	 */
+	info_event& operator=(const info_event& other);
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	info_event& operator=(info_event&& other) noexcept;
+
+	/**
+	 * @brief Type of this event.
+	 * @return Event type.
+	 */
+	event_type type(void) const;
+
+	/**
+	 * @brief Timestamp of the event as returned by the kernel.
+	 * @return Timestamp as a 64-bit unsigned integer.
+	 */
+	::std::uint64_t timestamp_ns(void) const noexcept;
+
+	/**
+	 * @brief Get the new line information.
+	 * @return Constant reference to the line info object containing the
+	 *         line data as read at the time of the info event.
+	 */
+	const line_info& get_line_info(void) const noexcept;
+
+private:
+
+	info_event(void);
+
+	struct impl;
+
+	::std::shared_ptr<impl> _m_priv;
+
+	friend chip;
+};
+
+/**
+ * @brief Stream insertion operator for info events.
+ * @param out Output stream to write to.
+ * @param event GPIO line info event to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const info_event& event);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_INFO_EVENT_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/line-config.hpp b/bindings/cxx/gpiodcxx/line-config.hpp
new file mode 100644
index 0000000..6d808bd
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/line-config.hpp
@@ -0,0 +1,564 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file line-config.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_LINE_CONFIG_HPP__
+#define __LIBGPIOD_CXX_LINE_CONFIG_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <any>
+#include <chrono>
+#include <cstddef>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <utility>
+
+namespace gpiod {
+
+class chip;
+class line_request;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Contains a set of line config options used in line requests and
+ *        reconfiguration.
+ */
+class line_config
+{
+public:
+
+	/**
+	 * @brief List of available configuration properties. Used in the
+	 *        constructor, :line_config::set_property_default and
+	 *        :line_config::set_property_override.
+	 */
+	enum class property {
+		DIRECTION = 1,
+		/**< Line direction. */
+		EDGE,
+		/**< Edge detection. */
+		BIAS,
+		/**< Bias. */
+		DRIVE,
+		/**< Drive. */
+		ACTIVE_LOW,
+		/**< Active-low setting. */
+		DEBOUNCE_PERIOD,
+		/**< Debounce period. */
+		EVENT_CLOCK,
+		/**< Event clock. */
+		OUTPUT_VALUE,
+		/**< Output value. */
+		OUTPUT_VALUES,
+		/**< Set of offset-to-value mappings. Only used in the constructor. */
+	};
+
+	/**
+	 * @brief List of configuration properties passed to the constructor.
+	 *        The first member is the property indicator, the second is
+	 *        the value stored as `std::any` that is interpreted by the
+	 *        relevant methods depending on the property value.
+	 */
+	using properties = ::std::map<property, ::std::any>;
+
+	/**
+	 * @brief Stored information about a single configuration override. The
+	 *        first member is the overridden line offset, the second is
+	 *        the property being overridden.
+	 */
+	using override = ::std::pair<line::offset, property>;
+
+	/**
+	 * @brief List of line configuration overrides.
+	 */
+	using override_list = ::std::vector<override>;
+
+	/**
+	 * @brief Constructor.
+	 * @param props List of configuration properties. See
+	 *              :set_property_default for details. Additionally the
+	 *              constructor takes another property type as argument:
+	 *              :property::OUTPUT_VALUES which takes
+	 *              :line::value_mappings as property value. This
+	 *              effectively sets the overrides for output values for
+	 *              the mapped offsets.
+	 */
+	explicit line_config(const properties& props = properties());
+
+	line_config(const line_config& other) = delete;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	line_config(line_config&& other) noexcept;
+
+	~line_config(void);
+
+	line_config& operator=(const line_config& other) = delete;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	line_config& operator=(line_config&& other) noexcept;
+
+	/**
+	 * @brief Reset the line config object.
+	 */
+	void reset(void) noexcept;
+
+	/**
+	 * @brief Set the default value of a single configuration property.
+	 * @param prop Property to set.
+	 * @param val Property value. The type must correspond with the
+	 *            property being set: :line::direction for
+	 *            :property::DIRECTION, :line::edge for :property::EDGE,
+	 *            :line::bias for :property::BIAS, :line::drive for
+	 *            :property::DRIVE, `bool` for :property::ACTIVE_LOW,
+	 *            `std::chrono:microseconds` for
+	 *            :property::DEBOUNCE_PERIOD, :line::clock for
+	 *            :property::EVENT_CLOCK and :line::value
+	 *            for :property::OUTPUT_VALUE.
+	 *
+	 */
+	void set_property_default(property prop, const ::std::any& val);
+
+	/**
+	 * @brief Set the override value of a single configuration property.
+	 * @param prop Property to set.
+	 * @param offset Line offset to override.
+	 * @param val Property value. See :set_property_default for details.
+	 */
+	void set_property_offset(property prop, line::offset offset, const ::std::any& val);
+
+	/**
+	 * @brief Set the default direction setting.
+	 * @param direction New direction.
+	 */
+	void set_direction_default(line::direction direction);
+
+	/**
+	 * @brief Set the direction for a single line at given offset.
+	 * @param direction New direction.
+	 * @param offset Offset of the line for which to set the direction.
+	 */
+	void set_direction_override(line::direction direction, line::offset offset);
+
+	/**
+	 * @brief Get the default direction setting.
+	 * @return Direction setting that would have been used for any offset
+	 * 	   not assigned its own direction value.
+	 */
+	line::direction direction_default(void) const;
+
+	/**
+	 * @brief Get the direction setting for a given offset.
+	 * @param offset Line offset for which to read the direction setting.
+	 * @return Direction setting that would have been used for given offset
+	 *         if the config object was used in a request at the time of
+	 *         the call.
+	 */
+	line::direction direction_offset(line::offset offset) const;
+
+	/**
+	 * @brief Clear the direction override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_direction_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the direction setting is overridden at given offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if direction is overridden at this offset, false
+	 *         otherwise.
+	 */
+	bool direction_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set the default edge event detection.
+	 * @param edge Type of edge events to detect.
+	 */
+	void set_edge_detection_default(line::edge edge);
+
+	/**
+	 * @brief Set the edge event detection for a single line at given
+	 *        offset.
+	 * @param edge Type of edge events to detect.
+	 * @param offset Offset of the line for which to set the direction.
+	 */
+	void set_edge_detection_override(line::edge edge, line::offset offset);
+
+	/**
+	 * @brief Get the default edge detection setting.
+	 * @return Edge detection setting that would have been used for any
+	 *         offset not assigned its own direction value.
+	 */
+	line::edge edge_detection_default(void) const;
+
+	/**
+	 * @brief Get the edge event detection setting for a given offset.
+	 * @param offset Line offset for which to read the edge detection
+	 *               setting.
+	 * @return Edge event detection setting that would have been used for
+	 * 	   given offset if the config object was used in a request at
+	 * 	   the time of the call.
+	 */
+	line::edge edge_detection_offset(line::offset offset) const;
+
+	/**
+	 * @brief Clear the edge detection override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_edge_detection_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the edge detection setting is overridden at given
+	 *        offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if edge detection is overridden at this offset, false
+	 *         otherwise.
+	 */
+	bool edge_detection_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set the default bias setting.
+	 * @param bias New bias.
+	 */
+	void set_bias_default(line::bias bias);
+
+	/**
+	 * @brief Set the bias for a single line at given offset.
+	 * @param bias New bias.
+	 * @param offset Offset of the line for which to set the bias.
+	 */
+	void set_bias_override(line::bias bias, line::offset offset);
+
+	/**
+	 * @brief Get the default bias setting.
+	 * @return Bias setting that would have been used for any offset not
+	 *         assigned its own direction value.
+	 */
+	line::bias bias_default(void) const;
+
+	/**
+	 * @brief Get the bias setting for a given offset.
+	 * @param offset Line offset for which to read the bias setting.
+	 * @return Bias setting that would have been used for given offset if
+	 *         the config object was used in a request at the time of the
+	 *         call.
+	 */
+	line::bias bias_offset(line::offset offset) const;
+
+	/**
+	 * @brief Clear the bias override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_bias_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the bias setting is overridden at given offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if bias is overridden at this offset, false otherwise.
+	 */
+	bool bias_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set the default drive setting.
+	 * @param drive New drive.
+	 */
+	void set_drive_default(line::drive drive);
+
+	/**
+	 * @brief Set the drive for a single line at given offset.
+	 * @param drive New drive.
+	 * @param offset Offset of the line for which to set the drive.
+	 */
+	void set_drive_override(line::drive drive, line::offset offset);
+
+	/**
+	 * @brief Set the drive for a subset of offsets.
+	 * @param drive New drive.
+	 * @param offsets Vector of line offsets for which to set the drive.
+	 */
+	void set_drive(line::drive drive, const line::offsets& offsets);
+
+	/**
+	 * @brief Get the default drive setting.
+	 * @return Drive setting that would have been used for any offset not
+	 *         assigned its own direction value.
+	 */
+	line::drive drive_default(void) const;
+
+	/**
+	 * @brief Get the drive setting for a given offset.
+	 * @param offset Line offset for which to read the drive setting.
+	 * @return Drive setting that would have been used for given offset if
+	 *         the config object was used in a request at the time of the
+	 *         call.
+	 */
+	line::drive drive_offset(line::offset offset) const;
+
+	/**
+	 * @brief Clear the drive override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_drive_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the drive setting is overridden at given offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if drive is overridden at this offset, false otherwise.
+	 */
+	bool drive_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set lines to active-low by default.
+	 * @param active_low New active-low setting.
+	 */
+	void set_active_low_default(bool active_low) noexcept;
+
+	/**
+	 * @brief Set a single line as active-low.
+	 * @param active_low New active-low setting.
+	 * @param offset Offset of the line for which to set the active setting.
+	 */
+	void set_active_low_override(bool active_low, line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if active-low is the default setting.
+	 * @return Active-low setting that would have been used for any offset
+         *         not assigned its own value.
+	 */
+	bool active_low_default(void) const noexcept;
+
+	/**
+	 * @brief Check if the line at given offset was configured as
+	 *        active-low.
+	 * @param offset Line offset for which to read the active-low setting.
+	 * @return Active-low setting that would have been used for given
+	 *         offset if the config object was used in a request at the
+	 *         time of the call.
+	 */
+	bool active_low_offset(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Clear the active-low override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_active_low_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the active-low setting is overridden at given offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if active-low is overridden at this offset, false
+	 *         otherwise.
+	 */
+	bool active_low_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set the default debounce period.
+	 * @param period New debounce period. Disables debouncing if 0.
+	 */
+	void set_debounce_period_default(const ::std::chrono::microseconds& period) noexcept;
+
+	/**
+	 * @brief Set the debounce period for a single line at given offset.
+	 * @param period New debounce period. Disables debouncing if 0.
+	 * @param offset Offset of the line for which to set the debounce
+	 *               period.
+	 */
+	void set_debounce_period_override(const ::std::chrono::microseconds& period,
+					     line::offset offset) noexcept;
+
+	/**
+	 * @brief Get the default debounce period.
+	 * @return Debounce period that would have been used for any offset not
+	 *         assigned its own debounce period. 0 if not debouncing is
+	 *         disabled.
+	 */
+	::std::chrono::microseconds debounce_period_default(void) const noexcept;
+
+	/**
+	 * @brief Get the debounce period for a given offset.
+	 * @param offset Line offset for which to read the debounce period.
+	 * @return Debounce period that would have been used for given offset
+	 *         if the config object was used in a request at the time of
+	 *         the call. 0 if debouncing is disabled.
+	 */
+	::std::chrono::microseconds debounce_period_offset(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Clear the debounce period override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_debounce_period_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the debounce period setting is overridden at given offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if debounce period is overridden at this offset, false
+	 *         otherwise.
+	 */
+	bool debounce_period_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set the default event timestamp clock.
+	 * @param clock New clock to use.
+	 */
+	void set_event_clock_default(line::clock clock);
+
+	/**
+	 * @brief Set the event clock for a single line at given offset.
+	 * @param clock New clock to use.
+	 * @param offset Offset of the line for which to set the event clock
+	 *               type.
+	 */
+	void set_event_clock_override(line::clock clock, line::offset offset);
+
+	/**
+	 * @brief Get the default event clock setting.
+	 * @return Event clock setting that would have been used for any offset
+	 *         not assigned its own direction value.
+	 */
+	line::clock event_clock_default(void) const;
+
+	/**
+	 * @brief Get the event clock setting for a given offset.
+	 * @param offset Line offset for which to read the event clock setting.
+	 * @return Event clock setting that would have been used for given
+	 *         offset if the config object was used in a request at the
+	 *         time of the call.
+	 */
+	line::clock event_clock_offset(line::offset offset) const;
+
+	/**
+	 * @brief Clear the event clock override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_event_clock_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the event clock setting is overridden at given
+	 *        offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if event clock is overridden at this offset, false
+	 *         otherwise.
+	 */
+	bool event_clock_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Set the default output value.
+	 * @param value New value.
+	 */
+	void set_output_value_default(line::value value) noexcept;
+
+	/**
+	 * @brief Set the output value for a single offset.
+	 * @param offset Line offset to associate the value with.
+	 * @param value New value.
+	 */
+	void set_output_value_override(line::value value, line::offset offset) noexcept;
+
+	/**
+	 * @brief Set the output values for a set of line offsets.
+	 * @param values Vector of offset->value mappings.
+	 */
+	void set_output_values(const line::value_mappings& values);
+
+	/**
+	 * @brief Set the output values for a set of line offsets.
+	 * @param offsets Vector of line offsets for which to set output values.
+	 * @param values Vector of new line values with indexes of values
+	 *               corresponding to the indexes of offsets.
+	 */
+	void set_output_values(const line::offsets& offsets, const line::values& values);
+
+	/**
+	 * @brief Get the default output value.
+	 * @return Output value that would have been used for any offset not
+	 *         assigned its own output value.
+	 */
+	line::value output_value_default(void) const noexcept;
+
+	/**
+	 * @brief Get the output value configured for a given line.
+	 * @param offset Line offset for which to read the value.
+	 * @return Output value that would have been used for given offset if
+	 *         the config object was used in a request at the time of the
+	 *         call.
+	 */
+	line::value output_value_offset(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Clear the output value override at given offset.
+	 * @param offset Offset of the line for which to clear the override.
+	 * @note Does nothing if no override is set for this line.
+	 */
+	void clear_output_value_override(line::offset offset) noexcept;
+
+	/**
+	 * @brief Check if the output value setting is overridden at given
+	 *        offset.
+	 * @param offset Offset of the line for which to check the override.
+	 * @return True if output value is overridden at this offset, false
+	 *         otherwise.
+	 */
+	bool output_value_is_overridden(line::offset offset) const noexcept;
+
+	/**
+	 * @brief Get the number of configuration overrides.
+	 * @return Number of overrides held by this object.
+	 */
+	::std::size_t num_overrides(void) const noexcept;
+
+	/**
+	 * @brief Get the list of property overrides.
+	 * @return List of configuration property overrides held by this object.
+	 */
+	override_list overrides(void) const;
+
+private:
+
+	struct impl;
+
+	::std::unique_ptr<impl> _m_priv;
+
+	friend chip;
+	friend line_request;
+};
+
+/**
+ * @brief Stream insertion operator for GPIO line config objects.
+ * @param out Output stream to write to.
+ * @param config Line config object to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const line_config& config);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_LINE_CONFIG_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/line-info.hpp b/bindings/cxx/gpiodcxx/line-info.hpp
new file mode 100644
index 0000000..e9883ab
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/line-info.hpp
@@ -0,0 +1,176 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file line-info.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_LINE_INFO_HPP__
+#define __LIBGPIOD_CXX_LINE_INFO_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <chrono>
+#include <iostream>
+#include <memory>
+#include <string>
+
+namespace gpiod {
+
+class chip;
+class info_event;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Contains an immutable snapshot of the line's state at the
+ *        time when the object of this class was instantiated.
+ */
+class line_info
+{
+public:
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy.
+	 */
+	line_info(const line_info& other) noexcept;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	line_info(line_info&& other) noexcept;
+
+	~line_info(void);
+
+	/**
+	 * @brief Copy assignment operator.
+	 * @param other Object to copy.
+	 * @return Reference to self.
+	 */
+	line_info& operator=(const line_info& other) noexcept;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	line_info& operator=(line_info&& other) noexcept;
+
+	/**
+	 * @brief Get the hardware offset of the line.
+	 * @return Offset of the line within the parent chip.
+	 */
+	line::offset offset(void) const noexcept;
+
+	/**
+	 * @brief Get the GPIO line name.
+	 * @return Name of the GPIO line as it is represented in the kernel.
+	 *         This routine returns an empty string if the line is unnamed.
+	 */
+	::std::string name(void) const noexcept;
+
+	/**
+	 * @brief Check if the line is currently in use.
+	 * @return True if the line is in use, false otherwise.
+	 *
+	 * The user space can't know exactly why a line is busy. It may have
+	 * been requested by another process or hogged by the kernel. It only
+	 * matters that the line is used and we can't request it.
+	 */
+	bool used(void) const noexcept;
+
+	/**
+	 * @brief Read the GPIO line consumer name.
+	 * @return Name of the GPIO consumer name as it is represented in the
+	 *         kernel. This routine returns an empty string if the line is
+	 *         not used.
+	 */
+	::std::string consumer(void) const noexcept;
+
+	/**
+	 * @brief Read the GPIO line direction setting.
+	 * @return Returns DIRECTION_INPUT or DIRECTION_OUTPUT.
+	 */
+	line::direction direction(void) const;
+
+	/**
+	 * @brief Read the current edge detection setting of this line.
+	 * @return Returns EDGE_NONE, EDGE_RISING, EDGE_FALLING or EDGE_BOTH.
+	 */
+	line::edge edge_detection(void) const;
+
+	/**
+	 * @brief Read the GPIO line bias setting.
+	 * @return Returns BIAS_PULL_UP, BIAS_PULL_DOWN, BIAS_DISABLE or
+	 *         BIAS_UNKNOWN.
+	 */
+	line::bias bias(void) const;
+
+	/**
+	 * @brief Read the GPIO line drive setting.
+	 * @return Returns DRIVE_PUSH_PULL, DRIVE_OPEN_DRAIN or
+	 *         DRIVE_OPEN_SOURCE.
+	 */
+	line::drive drive(void) const;
+
+	/**
+	 * @brief Check if the signal of this line is inverted.
+	 * @return True if this line is "active-low", false otherwise.
+	 */
+	bool active_low(void) const noexcept;
+
+	/**
+	 * @brief Check if this line is debounced (either by hardware or by the
+	 *        kernel software debouncer).
+	 * @return True if the line is debounced, false otherwise.
+	 */
+	bool debounced(void) const noexcept;
+
+	/**
+	 * @brief Read the current debounce period in microseconds.
+	 * @return Current debounce period in microseconds, 0 if the line is
+	 *         not debounced.
+	 */
+	::std::chrono::microseconds debounce_period(void) const noexcept;
+
+	/**
+	 * @brief Read the current event clock setting used for edge event
+	 *        timestamps.
+	 * @return Returns MONOTONIC or REALTIME.
+	 */
+	line::clock event_clock(void) const;
+
+private:
+
+	line_info(void);
+
+	struct impl;
+
+	::std::shared_ptr<impl> _m_priv;
+
+	friend chip;
+	friend info_event;
+};
+
+/**
+ * @brief Stream insertion operator for GPIO line info objects.
+ * @param out Output stream to write to.
+ * @param info GPIO line info object to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const line_info& info);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_LINE_INFO_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/line-request.hpp b/bindings/cxx/gpiodcxx/line-request.hpp
new file mode 100644
index 0000000..28ab6e1
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/line-request.hpp
@@ -0,0 +1,221 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file line-request.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_LINE_REQUEST_HPP__
+#define __LIBGPIOD_CXX_LINE_REQUEST_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <chrono>
+#include <cstddef>
+#include <iostream>
+#include <memory>
+
+#include "misc.hpp"
+
+namespace gpiod {
+
+class chip;
+class edge_event;
+class edge_event_buffer;
+class line_config;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Stores the context of a set of requested GPIO lines.
+ */
+class line_request
+{
+public:
+
+	line_request(const line_request& other) = delete;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	line_request(line_request&& other) noexcept;
+
+	~line_request(void);
+
+	line_request& operator=(const line_request& other) = delete;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 */
+	line_request& operator=(line_request&& other) noexcept;
+
+	/**
+	 * @brief Check if this object is valid.
+	 * @return True if this object's methods can be used, false otherwise.
+	 *         False usually means the request was released. If the user
+	 *         calls any of the methods of this class on an object for
+	 *         which this operator returned false, a logic_error will be
+	 *         thrown.
+	 */
+	explicit operator bool(void) const noexcept;
+
+	/**
+	 * @brief Release the GPIO chip and free all associated resources.
+	 * @note The object can still be used after this method is called but
+	 *       using any of the mutators will result in throwing
+	 *       a logic_error exception.
+	 */
+	void release(void);
+
+	/**
+	 * @brief Get the number of requested lines.
+	 * @return Number of lines in this request.
+	 */
+	::std::size_t num_lines(void) const;
+
+	/**
+	 * @brief Get the list of offsets of requested lines.
+	 * @return List of hardware offsets of the lines in this request.
+	 */
+	line::offsets offsets(void) const;
+
+	/**
+	 * @brief Get the value of a single requested line.
+	 * @param offset Offset of the line to read within the chip.
+	 * @return Current line value.
+	 */
+	line::value get_value(line::offset offset);
+
+	/**
+	 * @brief Get the values of a subset of requested lines.
+	 * @param offsets Vector of line offsets
+	 * @return Vector of lines values with indexes of values corresponding
+	 *         to those of the offsets.
+	 */
+	line::values get_values(const line::offsets& offsets);
+
+	/**
+	 * @brief Get the values of all requested lines.
+	 * @return List of read values.
+	 */
+	line::values get_values(void);
+
+	/**
+	 * @brief Get the values of a subset of requested lines into a vector
+	 *        supplied by the caller.
+	 * @param offsets Vector of line offsets.
+	 * @param values Vector for storing the values. Its size must be at
+	 *               least that of the offsets vector. The indexes of read
+	 *               values will correspond with those in the offsets
+	 *               vector.
+	 */
+	void get_values(const line::offsets& offsets, line::values& values);
+
+	/**
+	 * @brief Get the values of all requested lines.
+	 * @param values Array in which the values will be stored. Must hold
+	 *               at least the number of elements returned by
+	 *               line_request::num_lines.
+	 */
+	void get_values(line::values& values);
+
+	/**
+	 * @brief Set the value of a single requested line.
+	 * @param offset Offset of the line to set within the chip.
+	 * @param value New line value.
+	 */
+	void set_value(line::offset offset, line::value value);
+
+	/**
+	 * @brief Set the values of a subset of requested lines.
+	 * @param values Vector containing a set of offset->value mappings.
+	 */
+	void set_values(const line::value_mappings& values);
+
+	/**
+	 * @brief Set the values of a subset of requested lines.
+	 * @param offsets Vector containing the offsets of lines to set.
+	 * @param values Vector containing new values with indexes
+	 *               corresponding with those in the offsets vector.
+	 */
+	void set_values(const line::offsets& offsets, const line::values& values);
+
+	/**
+	 * @brief Set the values of all requested lines.
+	 * @param values Array of new line values. The size must be equal to
+	 *               the value returned by line_request::num_lines.
+	 */
+	void set_values(const line::values& values);
+
+	/**
+	 * @brief Apply new config options to requested lines.
+	 * @param config New configuration.
+	 */
+	void reconfigure_lines(const line_config& config);
+
+	/**
+	 * @brief Get the file descriptor number associated with this line
+	 *        request.
+	 * @return File descriptor number.
+	 */
+	int fd(void) const;
+
+	/**
+	 * @brief Wait for edge events on any of the lines requested with edge
+	 *        detection enabled.
+	 * @param timeout Wait time limit in nanoseconds.
+	 * @return True if at least one event is ready to be read. False if the
+	 *         wait timed out.
+	 */
+	bool wait_edge_event(const ::std::chrono::nanoseconds& timeout) const;
+
+	/**
+	 * @brief Read a number of edge events from this request up to the
+	 *        maximum capacity of the buffer.
+	 * @param buffer Edge event buffer to read events into.
+	 * @return Number of events read.
+	 */
+	::std::size_t read_edge_event(edge_event_buffer& buffer);
+
+	/**
+	 * @brief Read a number of edge events from this request.
+	 * @param buffer Edge event buffer to read events into.
+	 * @param max_events Maximum number of events to read. Limited by the
+	 *                   capacity of the buffer.
+	 * @return Number of events read.
+	 */
+	::std::size_t read_edge_event(edge_event_buffer& buffer, ::std::size_t max_events);
+
+private:
+
+	line_request(void);
+
+	struct impl;
+
+	::std::unique_ptr<impl> _m_priv;
+
+	friend chip;
+};
+
+/**
+ * @brief Stream insertion operator for line requests.
+ * @param out Output stream to write to.
+ * @param request Line request object to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const line_request& request);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_LINE_REQUEST_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/line.hpp b/bindings/cxx/gpiodcxx/line.hpp
new file mode 100644
index 0000000..8e8a984
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/line.hpp
@@ -0,0 +1,274 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file line.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_LINE_HPP__
+#define __LIBGPIOD_CXX_LINE_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <ostream>
+#include <utility>
+#include <vector>
+
+namespace gpiod {
+
+/**
+ * @brief Namespace containing various type definitions for GPIO lines.
+ */
+namespace line {
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Wrapper around unsigned int for representing line offsets.
+ */
+class offset
+{
+public:
+	/**
+	 * @brief Constructor with implicit conversion from unsigned int.
+	 * @param off Line offset.
+	 */
+	offset(unsigned int off = 0) : _m_offset(off) {	}
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy.
+	 */
+	offset(const offset& other) = default;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	offset(offset&& other) = default;
+
+	~offset(void) = default;
+
+	/**
+	 * @brief Assignment operator.
+	 * @param other Object to copy.
+	 * @return Reference to self.
+	 */
+	offset& operator=(const offset& other) = default;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	offset& operator=(offset&& other) noexcept = default;
+
+	/**
+	 * @brief Conversion operator to `unsigned int`.
+	 */
+	operator unsigned int(void) const noexcept
+	{
+		return this->_m_offset;
+	}
+
+private:
+	unsigned int _m_offset;
+};
+
+/**
+ * @brief Logical line states.
+ */
+enum class value
+{
+	INACTIVE = 0,
+	/**< Line is inactive. */
+	ACTIVE = 1,
+	/**< Line is active. */
+};
+
+/**
+ * @brief Direction settings.
+ */
+enum class direction
+{
+	AS_IS = 1,
+	/**< Request the line(s), but don't change current direction. */
+	INPUT,
+	/**< Direction is input - we're reading the state of a GPIO line. */
+	OUTPUT
+	/**< Direction is output - we're driving the GPIO line. */
+};
+
+/**
+ * @brief Edge detection settings.
+ */
+enum class edge
+{
+	NONE = 1,
+	/**< Line edge detection is disabled. */
+	RISING,
+	/**< Line detects rising edge events. */
+	FALLING,
+	/**< Line detect falling edge events. */
+	BOTH
+	/**< Line detects both rising and falling edge events. */
+};
+
+/**
+ * @brief Internal bias settings.
+ */
+enum class bias
+{
+	AS_IS = 1,
+	/**< Don't change the bias setting when applying line config. */
+	UNKNOWN,
+	/**< The internal bias state is unknown. */
+	DISABLED,
+	/**< The internal bias is disabled. */
+	PULL_UP,
+	/**< The internal pull-up bias is enabled. */
+	PULL_DOWN
+	/**< The internal pull-down bias is enabled. */
+};
+
+/**
+ * @brief Drive settings.
+ */
+enum class drive
+{
+	PUSH_PULL = 1,
+	/**< Drive setting is push-pull. */
+	OPEN_DRAIN,
+	/**< Line output is open-drain. */
+	OPEN_SOURCE
+	/**< Line output is open-source. */
+};
+
+/**
+ * @brief Event clock settings.
+ */
+enum class clock
+{
+	MONOTONIC = 1,
+	/**< Line uses the monotonic clock for edge event timestamps. */
+	REALTIME
+	/**< Line uses the realtime clock for edge event timestamps. */
+};
+
+/**
+ * @brief Vector of line offsets.
+ */
+using offsets = ::std::vector<offset>;
+
+/**
+ * @brief Vector of line values.
+ */
+using values = ::std::vector<value>;
+
+/**
+ * @brief Represents a mapping of a line offset to line logical state.
+ */
+using value_mapping = ::std::pair<offset, value>;
+
+/**
+ * @brief Vector of offset->value mappings. Each mapping is defined as a pair
+ *        of an unsigned and signed integers.
+ */
+using value_mappings = ::std::vector<value_mapping>;
+
+/**
+ * @brief Stream insertion operator for logical line values.
+ * @param out Output stream.
+ * @param val Value to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, value val);
+
+/**
+ * @brief Stream insertion operator for direction values.
+ * @param out Output stream.
+ * @param dir Value to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, direction dir);
+
+/**
+ * @brief Stream insertion operator for edge detection values.
+ * @param out Output stream.
+ * @param edge Value to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, edge edge);
+
+/**
+ * @brief Stream insertion operator for bias values.
+ * @param out Output stream.
+ * @param bias Value to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, bias bias);
+
+/**
+ * @brief Stream insertion operator for drive values.
+ * @param out Output stream.
+ * @param drive Value to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, drive drive);
+
+/**
+ * @brief Stream insertion operator for event clock values.
+ * @param out Output stream.
+ * @param clock Value to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, clock clock);
+
+/**
+ * @brief Stream insertion operator for the list of output values.
+ * @param out Output stream.
+ * @param vals Object to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const values& vals);
+
+/**
+ * @brief Stream insertion operator for the list of line offsets.
+ * @param out Output stream.
+ * @param offs Object to insert into the output stream in a human-readable form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const offsets& offs);
+
+/**
+ * @brief Stream insertion operator for the offset-to-value mapping.
+ * @param out Output stream.
+ * @param mapping Value to insert into the output stream in a human-readable
+ *        form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const value_mapping& mapping);
+
+/**
+ * @brief Stream insertion operator for the list of offset-to-value mappings.
+ * @param out Output stream.
+ * @param mappings Object to insert into the output stream in a human-readable
+ *        form.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const value_mappings& mappings);
+
+/**
+ * @}
+ */
+
+} /* namespace line */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_LINE_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/misc.hpp b/bindings/cxx/gpiodcxx/misc.hpp
new file mode 100644
index 0000000..6e0084b
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/misc.hpp
@@ -0,0 +1,44 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file misc.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_MISC_HPP__
+#define __LIBGPIOD_CXX_MISC_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <string>
+
+namespace gpiod {
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Check if the file pointed to by path is a GPIO chip character device.
+ * @param path Path to check.
+ * @return True if the file exists and is a GPIO chip character device or a
+ *         symbolic link to it.
+ */
+bool is_gpiochip_device(const ::std::filesystem::path& path);
+
+/**
+ * @brief Get the human readable version string for libgpiod API
+ * @return String containing the library version.
+ */
+const ::std::string& version_string(void);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_MISC_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/request-config.hpp b/bindings/cxx/gpiodcxx/request-config.hpp
new file mode 100644
index 0000000..52444c9
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/request-config.hpp
@@ -0,0 +1,163 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2021 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file request-config.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_REQUEST_CONFIG_HPP__
+#define __LIBGPIOD_CXX_REQUEST_CONFIG_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <any>
+#include <cstddef>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+
+#include "line.hpp"
+
+namespace gpiod {
+
+class chip;
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Stores a set of options passed to the kernel when making a line
+ *        request.
+ */
+class request_config
+{
+public:
+
+	/**
+	 * @brief List of available configuration settings. Used in the
+	 *        constructor and :request_config::set_property.
+	 */
+	enum class property {
+		OFFSETS = 1,
+		/**< List of line offsets to request. */
+		CONSUMER,
+		/**< Consumer string. */
+		EVENT_BUFFER_SIZE,
+		/**< Suggested size of the edge event buffer. */
+	};
+
+	/**
+	 * @brief Map of mappings between property types and property values.
+	 */
+	using properties = ::std::map<property, ::std::any>;
+
+	/**
+	 * @brief Constructor.
+	 * @param props List of config properties. See
+	 *              :request_config::set_property.
+	 */
+	explicit request_config(const properties& props = properties());
+
+	request_config(const request_config& other) = delete;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	request_config(request_config&& other) noexcept;
+
+	~request_config(void);
+
+	request_config& operator=(const request_config& other) = delete;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	request_config& operator=(request_config&& other) noexcept;
+
+	/**
+	 * @brief Set the value of a single config property.
+	 * @param prop Property to set.
+	 * @param val Property value. The type must correspond to the property
+	 *            being set: `std::string` or `const char*` for
+	 *            :property::CONSUMER, `:line::offsets` for
+	 *            :property::OFFSETS and `unsigned long` for
+	 *            :property::EVENT_BUFFER_SIZE.
+	 */
+	void set_property(property prop, const ::std::any& val);
+
+	/**
+	 * @brief Set line offsets for this request.
+	 * @param offsets Vector of line offsets to request.
+	 */
+	void set_offsets(const line::offsets& offsets) noexcept;
+
+	/**
+	 * @brief Get the number of offsets configured in this request config.
+	 * @return Number of line offsets in this request config.
+	 */
+	::std::size_t num_offsets(void) const noexcept;
+
+	/**
+	 * @brief Set the consumer name.
+	 * @param consumer New consumer name.
+	 */
+	void set_consumer(const ::std::string& consumer) noexcept;
+
+	/**
+	 * @brief Get the consumer name.
+	 * @return Currently configured consumer name. May be an empty string.
+	 */
+	::std::string consumer(void) const noexcept;
+
+	/**
+	 * @brief Get the hardware offsets of lines in this request config.
+	 * @return List of line offsets.
+	 */
+	line::offsets offsets(void) const;
+
+	/**
+	 * @brief Set the size of the kernel event buffer.
+	 * @param event_buffer_size New event buffer size.
+	 * @note The kernel may adjust the value if it's too high. If set to 0,
+	 *       the default value will be used.
+	 */
+	void set_event_buffer_size(::std::size_t event_buffer_size) noexcept;
+
+	/**
+	 * @brief Get the edge event buffer size from this request config.
+	 * @return Current edge event buffer size setting.
+	 */
+	::std::size_t event_buffer_size(void) const noexcept;
+
+private:
+
+	struct impl;
+
+	::std::unique_ptr<impl> _m_priv;
+
+	friend chip;
+};
+
+/**
+ * @brief Stream insertion operator for request_config objects.
+ * @param out Output stream to write to.
+ * @param config request_config to insert into the output stream.
+ * @return Reference to out.
+ */
+::std::ostream& operator<<(::std::ostream& out, const request_config& config);
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_REQUEST_CONFIG_HPP__ */
diff --git a/bindings/cxx/gpiodcxx/timestamp.hpp b/bindings/cxx/gpiodcxx/timestamp.hpp
new file mode 100644
index 0000000..d707fee
--- /dev/null
+++ b/bindings/cxx/gpiodcxx/timestamp.hpp
@@ -0,0 +1,122 @@ 
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/**
+ * @file timestamp.hpp
+ */
+
+#ifndef __LIBGPIOD_CXX_TIMESTAMP_HPP__
+#define __LIBGPIOD_CXX_TIMESTAMP_HPP__
+
+#if !defined(__LIBGPIOD_GPIOD_CXX_INSIDE__)
+#error "Only gpiod.hpp can be included directly."
+#endif
+
+#include <chrono>
+#include <cstdint>
+
+namespace gpiod {
+
+/**
+ * @ingroup gpiod_cxx
+ * @{
+ */
+
+/**
+ * @brief Stores the edge and info event timestamps as returned by the kernel
+ *        and allows to convert them to std::chrono::time_point.
+ */
+class timestamp
+{
+public:
+
+	/**
+	 * @brief Monotonic time_point.
+	 */
+	using time_point_monotonic = ::std::chrono::time_point<::std::chrono::steady_clock>;
+
+	/**
+	 * @brief Real-time time_point.
+	 */
+	using time_point_realtime = ::std::chrono::time_point<::std::chrono::system_clock>;
+
+	/**
+	 * @brief Constructor with implicit  conversion from `uint64_t`.
+	 * @param ns Timestamp in nanoseconds.
+	 */
+	timestamp(::std::uint64_t ns) : _m_ns(ns) { }
+
+	/**
+	 * @brief Copy constructor.
+	 * @param other Object to copy.
+	 */
+	timestamp(const timestamp& other) noexcept = default;
+
+	/**
+	 * @brief Move constructor.
+	 * @param other Object to move.
+	 */
+	timestamp(timestamp&& other) noexcept = default;
+
+	/**
+	 * @brief Assignment operator.
+	 * @param other Object to copy.
+	 * @return Reference to self.
+	 */
+	timestamp& operator=(const timestamp& other) noexcept = default;
+
+	/**
+	 * @brief Move assignment operator.
+	 * @param other Object to move.
+	 * @return Reference to self.
+	 */
+	timestamp& operator=(timestamp&& other) noexcept = default;
+
+	~timestamp(void) = default;
+
+	/**
+	 * @brief Conversion operator to `std::uint64_t`.
+	 */
+	operator ::std::uint64_t(void) noexcept
+	{
+		return this->ns();
+	}
+
+	/**
+	 * @brief Get the timestamp in nanoseconds.
+	 * @return Timestamp in nanoseconds.
+	 */
+	::std::uint64_t ns(void) const noexcept
+	{
+		return this->_m_ns;
+	}
+
+	/**
+	 * @brief Convert the timestamp to a monotonic time_point.
+	 * @return time_point associated with the steady clock.
+	 */
+	time_point_monotonic to_time_point_monotonic(void) const
+	{
+		return time_point_monotonic(::std::chrono::nanoseconds(this->ns()));
+	}
+
+	/**
+	 * @brief Convert the timestamp to a real-time time_point.
+	 * @return time_point associated with the system clock.
+	 */
+	time_point_realtime to_time_point_realtime(void) const
+	{
+		return time_point_realtime(::std::chrono::nanoseconds(this->ns()));
+	}
+
+private:
+	::std::uint64_t _m_ns;
+};
+
+/**
+ * @}
+ */
+
+} /* namespace gpiod */
+
+#endif /* __LIBGPIOD_CXX_TIMESTAMP_HPP__ */
diff --git a/configure.ac b/configure.ac
index f8d34ed..ab03673 100644
--- a/configure.ac
+++ b/configure.ac
@@ -239,6 +239,7 @@  AC_CONFIG_FILES([Makefile
 		 bindings/cxx/libgpiodcxx.pc
 		 bindings/Makefile
 		 bindings/cxx/Makefile
+		 bindings/cxx/gpiodcxx/Makefile
 		 bindings/cxx/examples/Makefile
 		 bindings/cxx/tests/Makefile
 		 bindings/python/Makefile