diff --git a/CMakeLists.txt b/CMakeLists.txt index b4a1905..d956d80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ if (APPLE) set(INSTALL_RPATH_USE_LINK_PATH ON) endif() -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/README.md b/README.md index 61a9822..1ea5c04 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![action](https://github.com/speediegq/docpp/actions/workflows/cmake-multi-platform.yml/badge.svg) -C++11 library for generating HTML, CSS and SGML-like documents. +C++17 library for generating HTML, CSS and SGML-like documents. ## Features diff --git a/include/docpp.hpp b/include/docpp.hpp index b090820..0e06888 100644 --- a/include/docpp.hpp +++ b/include/docpp.hpp @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include /** @@ -26,7 +24,7 @@ namespace docpp { private: const char* message{"Out of range"}; public: - const char* what() const noexcept override { + [[nodiscard]] const char* what() const noexcept override { return message; } out_of_range() = default; @@ -40,7 +38,7 @@ namespace docpp { private: const char* message{"Invalid argument"}; public: - const char* what() const noexcept override { + [[nodiscard]] const char* what() const noexcept override { return message; } invalid_argument() = default; @@ -233,7 +231,7 @@ namespace docpp { * @param tag The tag to resolve * @return std::pair The resolved tag */ - std::pair resolve_tag(const Tag tag); + std::pair resolve_tag(Tag tag); /** * @brief Resolve a string tag to a Tag enum. * @param tag The tag to resolve @@ -254,7 +252,7 @@ namespace docpp { /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Construct a new Property object @@ -266,7 +264,7 @@ namespace docpp { * @brief Construct a new Property object * @param property The property to set */ - Property(const Property& property) : property(property.property) {}; + Property(const Property& property) = default; /** * @brief Construct a new Property object */ @@ -280,14 +278,14 @@ namespace docpp { * @brief Get the key of the property * @return std::string The key of the property */ - std::string get_key() const; + [[nodiscard]] std::string get_key() const; /** * @brief Get the key of the property in a specific type * @return T The key of the property */ template T get_key() const { - if (std::is_same::value) { - return this->property.first; + if (std::is_same_v) { + return this->property.first; } return T(this->property.first); @@ -296,13 +294,13 @@ namespace docpp { * @brief Get the value of the property * @return std::string The value of the property */ - std::string get_value() const; + [[nodiscard]] std::string get_value() const; /** * @brief Get the value of the property in a specific type * @return T The value of the property */ template T get_value() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->property.second; } return T(this->property.second); @@ -311,13 +309,13 @@ namespace docpp { * @brief Get the property. * @return std::pair The value of the property */ - std::pair get() const; + [[nodiscard]] std::pair get() const; /** * @brief Get the property in a specific type. * @return std::pair The value of the property */ template std::pair get() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->property; } @@ -346,7 +344,7 @@ namespace docpp { * @brief Check if the property is empty * @return bool True if the property is empty, false otherwise */ - bool empty() const; + [[nodiscard]] bool empty() const; Property& operator=(const Property& property); bool operator==(const Property& property) const; @@ -378,16 +376,26 @@ namespace docpp { * @return iterator The iterator to the end. */ iterator end() { return properties.end(); } + /** + * @brief Return an iterator to the beginning. + * @return iterator The iterator to the beginning. + */ + [[nodiscard]] const_iterator begin() const { return properties.begin(); } + /** + * @brief Return an iterator to the end. + * @return iterator The iterator to the end. + */ + [[nodiscard]] const_iterator end() const { return properties.end(); } /** * @brief Return a const iterator to the beginning. * @return const_iterator The const iterator to the beginning. */ - const_iterator cbegin() const { return properties.cbegin(); } + [[nodiscard]] const_iterator cbegin() const { return properties.cbegin(); } /** * @brief Return a const iterator to the end. * @return const_iterator The const iterator to the end. */ - const_iterator cend() const { return properties.cend(); } + [[nodiscard]] const_iterator cend() const { return properties.cend(); } /** * @brief Return a reverse iterator to the beginning. * @return reverse_iterator The reverse iterator to the beginning. @@ -402,23 +410,23 @@ namespace docpp { * @brief Return a const reverse iterator to the beginning. * @return const_reverse_iterator The const reverse iterator to the beginning. */ - const_reverse_iterator crbegin() { return properties.crbegin(); } + [[nodiscard]] const_reverse_iterator crbegin() const { return properties.crbegin(); } /** * @brief Return a const reverse iterator to the end. * @return const_reverse_iterator The const reverse iterator to the end. */ - const_reverse_iterator crend() { return properties.crend(); } + [[nodiscard]] const_reverse_iterator crend() const { return properties.crend(); } /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Get the properties of the element * @return std::vector The properties of the element */ - std::vector get_properties() const; + [[nodiscard]] std::vector get_properties() const; /** * @brief Set the properties of the element * @param properties The properties to set @@ -429,57 +437,57 @@ namespace docpp { * @param index The index of the property * @return Property The property at the index */ - Property at(const size_type index) const; + [[nodiscard]] Property at(size_type index) const; /** * @brief Insert a property into the element * @param index The index to insert the property * @param property The property to insert */ - void insert(const size_type index, const Property& property); + void insert(size_type index, const Property& property); /** * @brief Erase a property from the element * @param index The index of the property to erase */ - void erase(const size_type index); + void erase(size_type index); /** * @brief Find a property in the element * @param property The property to find * @return size_type The index of the property */ - size_type find(const Property& property); + [[nodiscard]] size_type find(const docpp::HTML::Property &property) const; /** * @brief Find a property in the element * @param str The property to find * @return size_type The index of the property */ - size_type find(const std::string& str); + [[nodiscard]] size_type find(const std::string& str) const; /** * @brief Swap two properties in the element * @param index1 The index of the first property * @param index2 The index of the second property */ - void swap(const size_type index1, const size_type index2); + void swap(size_type index1, size_type index2); /** * @brief Swap two properties in the element * @param property1 The first property * @param property2 The second property */ - void swap(const Property& property1, const Property& property2); + void swap(const docpp::HTML::Property &property1, const docpp::HTML::Property &property2); /** * @brief Get the first property of the element * @return Property The first property of the element */ - Property front() const; + [[nodiscard]] Property front() const; /** * @brief Get the last property of the element * @return Property The last property of the element */ - Property back() const; + [[nodiscard]] Property back() const; /** * @brief Get the size of the element * @return size_type The size of the element */ - size_type size() const; + [[nodiscard]] size_type size() const; /** * @brief Clear the properties */ @@ -488,7 +496,7 @@ namespace docpp { * @brief Check if the properties are empty * @return bool True if the properties are empty, false otherwise */ - bool empty() const; + [[nodiscard]] bool empty() const; /** * @brief Prepend a property to the element * @param property The property to add @@ -499,21 +507,22 @@ namespace docpp { * @param property The property to add */ void push_back(const Property& property); + template explicit Properties(Args... args) { (this->push_back(args), ...); } /** * @brief Construct a new Properties object * @param properties The properties to set */ - Properties(const std::vector& properties) : properties(properties) {}; + explicit Properties(const std::vector& properties) : properties(properties) {}; /** * @brief Construct a new Properties object * @param property The property to add */ - Properties(const Property& property) : properties({property}) {}; + explicit Properties(const Property& property) : properties({property}) {}; /** * @brief Construct a new Properties object * @param properties The properties to set */ - Properties(const Properties& properties) : properties(properties.properties) {}; + Properties(const Properties& properties) = default; /** * @brief Construct a new Properties object */ @@ -522,7 +531,6 @@ namespace docpp { * @brief Destroy the Properties object */ ~Properties() = default; - Properties& operator=(const Properties& properties); Properties& operator=(const std::vector& properties); Properties& operator=(const Property& property); @@ -541,16 +549,16 @@ namespace docpp { class Element { private: std::string tag{}; + Properties properties{}; std::string data{}; Type type{Type::Non_Self_Closing}; - Properties properties{}; protected: public: using size_type = std::size_t; /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Construct a new Element object @@ -559,19 +567,19 @@ namespace docpp { * @param data The data of the element * @param type The close tag type. */ - Element(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, const Type type = Type::Non_Self_Closing) : tag(tag), properties(properties), data(data), type(type) {}; + explicit Element(std::string tag, const Properties& properties = {}, std::string data = {}, const Type& type = Type::Non_Self_Closing) : tag(std::move(tag)), properties(properties), data(std::move(data)), type(type) {}; /** * @brief Construct a new Element object * @param tag The tag of the element * @param properties The properties of the element * @param data The data of the element */ - Element(const Tag tag, const Properties& properties = {}, const std::string& data = {}) : tag(resolve_tag(tag).first), properties(properties), data(data), type(resolve_tag(tag).second) {}; + explicit Element(const Tag tag, const Properties& properties = {}, std::string data = {}) : tag(resolve_tag(tag).first), properties(properties), data(std::move(data)), type(resolve_tag(tag).second) {}; /** * @brief Construct a new Element object * @param element The element to set */ - Element(const Element& element) : tag(element.tag), properties(element.properties), data(element.data), type(element.type) {}; + Element(const Element& element) = default; /** * @brief Construct a new Element object */ @@ -587,14 +595,14 @@ namespace docpp { * @param data The data of the element * @param type The close tag type. */ - void set(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, const Type type = Type::Non_Self_Closing); + void set(const std::string& tag, const Properties& properties = {}, const std::string& data = {}, Type type = Type::Non_Self_Closing); /** * @brief Set the tag, properties, and data of the element * @param tag The tag of the element * @param properties The properties of the element * @param data The data of the element */ - void set(const Tag tag, const Properties& properties = {}, const std::string& data = {}); + void set(Tag tag, const Properties& properties = {}, const std::string& data = {}); /** * @brief Set the tag of the element * @param tag The tag of the element @@ -604,7 +612,7 @@ namespace docpp { * @brief Set the tag of the element * @param tag The tag of the element */ - void set_tag(const Tag tag); + void set_tag(Tag tag); /** * @brief Set the data of the element * @param data The data of the element @@ -619,19 +627,19 @@ namespace docpp { * @brief Set the type of the element * @param type The type of the element */ - void set_type(const Type type); + void set_type(Type type); /** * @brief Get the element in the form of an HTML tag. * @return std::string The tag of the element */ - std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; + [[nodiscard]] std::string get(Formatting formatting = Formatting::None, int tabc = 0) const; /** * @brief Get the element in the form of a specific type. * @return T The element in the form of a specific type */ template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { - if (std::is_same::value) { + if (std::is_same_v) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); @@ -641,13 +649,13 @@ namespace docpp { * @brief Get the tag of the element * @return std::string The data of the element */ - std::string get_tag() const; + [[nodiscard]] std::string get_tag() const; /** * @brief Get the tag of the element in a specific type * @return T The tag of the element */ template T get_tag() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->tag; } return T(this->tag); @@ -657,13 +665,13 @@ namespace docpp { * @brief Get the data of the element * @return std::string The data of the element */ - std::string get_data() const; + [[nodiscard]] std::string get_data() const; /** * @brief Get the data of the element in a specific type * @return T The data of the element */ template T get_data() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->data; } return T(this->data); @@ -672,12 +680,12 @@ namespace docpp { * @brief Get the properties of the element * @return Properties The properties of the element */ - Properties get_properties() const; + [[nodiscard]] Properties get_properties() const; /** * @brief Get the type of the element * @return Type The type of the element */ - Type get_type() const; + [[nodiscard]] Type get_type() const; /** * @brief Clear the element */ @@ -686,7 +694,7 @@ namespace docpp { * @brief Check if the element is empty. * @return bool True if the element is empty, false otherwise. */ - bool empty() const; + [[nodiscard]] bool empty() const; Element& operator=(const Element& element); Element& operator+=(const std::string& data); @@ -710,17 +718,31 @@ namespace docpp { private: T element{}; public: - sect_iterator(const T& element) : element(element) {} - sect_iterator operator++() { return ++element; } - Element operator*() { return element->second; } - bool operator==(const sect_iterator& other) { return element == other.element; } - bool operator!=(const sect_iterator& other) { return element != other.element; } + explicit sect_iterator(const T& element) : element(element) {} + sect_iterator& operator++() { + ++element; + return *this; + } + + auto operator*() const -> decltype(element->second) { + return element->second; + } + + bool operator==(const sect_iterator& other) const { + return element == other.element; + } + + bool operator!=(const sect_iterator& other) const { + return element != other.element; + } }; - using iterator = sect_iterator::iterator>; - using const_iterator = sect_iterator::const_iterator>; - using reverse_iterator = sect_iterator::reverse_iterator>; - using const_reverse_iterator = sect_iterator::const_reverse_iterator>; + + using element_map = std::map; + using iterator = sect_iterator; + using const_iterator = sect_iterator; + using reverse_iterator = sect_iterator; + using const_reverse_iterator = sect_iterator; /** * @brief Return an iterator to the beginning. @@ -732,16 +754,26 @@ namespace docpp { * @return iterator The iterator to the end. */ iterator end() { return iterator(elements.end()); } + /** + * @brief Return an iterator to the beginning. + * @return const_iterator The iterator to the beginning. + */ + [[nodiscard]] const_iterator begin() const { return const_iterator(elements.begin()); } + /** + * @brief Return an iterator to the end. + * @return const_iterator The iterator to the end. + */ + [[nodiscard]] const_iterator end() const { return const_iterator(elements.end()); } /** * @brief Return a const iterator to the beginning. * @return const_iterator The const iterator to the beginning. */ - const_iterator cbegin() const { return const_iterator(elements.cbegin()); } + [[nodiscard]] const_iterator cbegin() const { return const_iterator(elements.cbegin()); } /** * @brief Return a const iterator to the end. * @return const_iterator The const iterator to the end. */ - const_iterator cend() const { return const_iterator(elements.cend()); } + [[nodiscard]] const_iterator cend() const { return const_iterator(elements.cend()); } /** * @brief Return a reverse iterator to the beginning. * @return reverse_iterator The reverse iterator to the beginning. @@ -756,17 +788,17 @@ namespace docpp { * @brief Return a const reverse iterator to the beginning. * @return const_reverse_iterator The const reverse iterator to the beginning. */ - const_reverse_iterator crbegin() { return const_reverse_iterator(elements.crbegin()); } + [[nodiscard]] const_reverse_iterator crbegin() const { return const_reverse_iterator(elements.crbegin()); } /** * @brief Return a const reverse iterator to the end. * @return const_reverse_iterator The const reverse iterator to the end. */ - const_reverse_iterator crend() { return const_reverse_iterator(elements.crend()); } + [[nodiscard]] const_reverse_iterator crend() const { return const_reverse_iterator(elements.crend()); } /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Prepend an element to the section @@ -788,35 +820,37 @@ namespace docpp { * @param section The section to add */ void push_back(const Section& section); + /** * @brief Get the element at an index. To get a section, use at_section() * @param index The index of the element * @return Element The element at the index */ - Element at(const size_type index) const; + [[nodiscard]] Element at(size_type index) const; /** * @brief Get the section at an index. To get an element, use at() * @param index The index of the section * @return Section The section at the index */ - Section at_section(const size_type index) const; + [[nodiscard]] Section at_section(size_type index) const; /** * @brief Get the element at an index. To get a section, use at_section() * @param index The index of the element * @return Element The element at the index */ - Element& at(const size_type index); + Element& at(size_type index); /** * @brief Get the section at an index. To get an element, use at() * @param index The index of the section * @return Section The section at the index */ - Section& at_section(const size_type index); + Section& at_section(size_type index); + /** * @brief Erase an element from the section. Note that this will NOT change the size/index. * @param index The index of the element to erase */ - void erase(const size_type index); + void erase(size_type index); /** * @brief Erase a section from the section, by reading from a section. The section will be erased if it's identical to section. Note that this will NOT change the size/index. * @param section The section to erase @@ -832,36 +866,36 @@ namespace docpp { * @param element The element to find * @return size_type The index of the element */ - size_type find(const Element& element); + [[nodiscard]] size_type find(const Element& element) const; /** * @brief Find a section in the section * @param section The section to find * @return size_type The index of the section */ - size_type find(const Section& section); + [[nodiscard]] size_type find(const Section& section) const; /** * @brief Find an element or section in the section * @param str The element or section to find * @return size_type The index of the element or section */ - size_type find(const std::string& str); + [[nodiscard]] size_type find(const std::string& str) const; /** * @brief Insert an element into the section * @param index The index to insert the element * @param element The element to insert */ - void insert(const size_type index, const Element& element); + void insert(size_type index, const Element& element); /** * @brief Insert a section into the section * @param index The index to insert the section * @param section The section to insert */ - void insert(const size_type index, const Section& section); + void insert(size_type index, const Section& section); /** * @brief Get the first element of the section * @return Element The first element of the section */ - Element front() const; + [[nodiscard]] Element front() const; /** * @brief Get the first element of the section * @return Element The first element of the section @@ -871,7 +905,7 @@ namespace docpp { * @brief Get the last element of the section * @return Element The last element of the section */ - Element back() const; + [[nodiscard]] Element back() const; /** * @brief Get the last element of the section * @return Element The last element of the section @@ -881,7 +915,7 @@ namespace docpp { * @brief Get the first section of the section * @return Section The first section of the section */ - Section front_section() const; + [[nodiscard]] Section front_section() const; /** * @brief Get the first section of the section * @return Section The first section of the section @@ -891,17 +925,17 @@ namespace docpp { * @brief Get the last section of the section * @return Section The last section of the section */ - Section back_section() const; + [[nodiscard]] Section back_section() const; /** * @brief Get the last section of the section * @return Section The last section of the section */ - Section& back_section(); + [[nodiscard]] Section& back_section(); /** * @brief Get the size of the section * @return size_type The size of the section */ - size_type size() const; + [[nodiscard]] size_type size() const; /** * @brief Clear the section */ @@ -910,27 +944,26 @@ namespace docpp { * @brief Check if the section is empty * @return bool True if the section is empty, false otherwise */ - bool empty() const; - + [[nodiscard]] bool empty() const; /** * @brief Construct a new Section object * @param tag The tag of the section * @param properties The properties of the section */ - Section(const std::string& tag, const Properties& properties = {}) : tag(tag), properties(properties) {}; + explicit Section(std::string tag, const Properties& properties = {}) : tag(std::move(tag)), properties(properties) {}; /** * @brief Construct a new Section object * @param tag The tag of the section * @param properties The properties of the section */ - Section(const Tag tag, const Properties& properties = {}) : tag(resolve_tag(tag).first), properties(properties) {}; + explicit Section(const Tag tag, const Properties& properties = {}) : tag(resolve_tag(tag).first), properties(properties) {}; /** * @brief Construct a new Section object * @param tag The tag of the section * @param properties The properties of the section * @param elements The elements of the section */ - Section(const std::string& tag, const Properties& properties, const std::vector& elements) : tag(tag), properties(properties) { + Section(std::string tag, const Properties& properties, const std::vector& elements) : tag(std::move(tag)), properties(properties) { for (const auto& element : elements) this->push_back(element); }; /** @@ -948,7 +981,7 @@ namespace docpp { * @param properties The properties of the section * @param sections The sections of the section */ - Section(const std::string& tag, const Properties& properties, const std::vector
& sections) : tag(tag), properties(properties) { + Section(std::string tag, const Properties& properties, const std::vector
& sections) : tag(std::move(tag)), properties(properties) { for (const auto& section : sections) this->push_back(section); }; /** @@ -980,19 +1013,17 @@ namespace docpp { */ ~Section() = default; /** - * @brief Set the tag, id, and classes of the section - * @param tag The tag of the section - * @param id The id of the section - * @param classes The classes of the section + * @brief Set the tag and properties of the section + * @param tag The tag to assign to the section + * @param properties The properties to assign to the section tag */ void set(const std::string& tag, const Properties& properties = {}); /** * @brief Set the tag, id, and classes of the section * @param tag The tag of the section - * @param id The id of the section - * @param classes The classes of the section + * @param properties The properties to assign the tag */ - void set(const Tag tag, const Properties& properties = {}); + void set(Tag tag, const Properties& properties = {}); /** * @brief Set the tag of the section * @param tag The tag of the section @@ -1002,7 +1033,7 @@ namespace docpp { * @brief Set the tag of the section * @param tag The tag of the section */ - void set_tag(const Tag tag); + void set_tag(Tag tag); /** * @brief Set the properties of the section * @param properties The properties of the section @@ -1013,7 +1044,7 @@ namespace docpp { * @param index1 The index of the first element * @param index2 The index of the second element */ - void swap(const size_type index1, const size_type index2); + void swap(size_type index1, size_type index2); /** * @brief Swap two elements in the section * @param element1 The first element @@ -1022,32 +1053,32 @@ namespace docpp { void swap(const Element& element1, const Element& element2); /** * @brief Swap two sections in the section - * @param index1 The index of the first section - * @param index2 The index of the second section + * @param section1 The first section + * @param section2 The second section */ void swap(const Section& section1, const Section& section2); /** * @brief Get the elements of the section * @return std::vector The elements of the section */ - std::vector get_elements() const; + [[nodiscard]] std::vector get_elements() const; /** * @brief Get the sections of the section * @return std::vector
The sections of the section */ - std::vector
get_sections() const; + [[nodiscard]] std::vector
get_sections() const; /** * @brief Dump the entire section. * @return std::string The section */ - std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; + [[nodiscard]] std::string get(Formatting formatting = Formatting::None, int tabc = 0) const; /** * @brief Get the element in the form of a specific type. * @return T The element in the form of a specific type */ template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { - if (std::is_same::value) { + if (std::is_same_v) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); @@ -1057,13 +1088,13 @@ namespace docpp { * @brief Get the tag of the section * @return std::string The tag of the section */ - std::string get_tag() const; + [[nodiscard]] std::string get_tag() const; /** * @brief Get the tag of the section in a specific type * @return T The tag of the section */ template T get_tag() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->tag; } return T(this->tag); @@ -1072,7 +1103,7 @@ namespace docpp { * @brief Get the properties of the section * @return Properties The properties of the section */ - Properties get_properties() const; + [[nodiscard]] Properties get_properties() const; Section& operator=(const Section& section); Section& operator+=(const Element& element); @@ -1083,14 +1114,14 @@ namespace docpp { bool operator!=(const Section& section) const; Element operator[](const int& index) const; std::unordered_map operator[](const std::string& tag) const; - std::unordered_map operator[](const Tag tag) const; + std::unordered_map operator[](Tag tag) const; private: size_type index{}; std::string tag{}; Properties properties{}; - std::map elements{}; - std::unordered_map sections{}; + std::map elements{}; + std::unordered_map sections{}; }; /** @@ -1098,8 +1129,8 @@ namespace docpp { */ class Document { private: - std::string doctype{""}; Section document{}; + std::string doctype{""}; protected: public: using size_type = std::size_t; @@ -1107,20 +1138,21 @@ namespace docpp { /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Get the document - * @param std::string The type to return + * @param formatting The formatting type to use + * @param tabc Number of tab indents to start with, when using Formatting::Pretty * @return std::string The document */ - std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; + [[nodiscard]] std::string get(Formatting formatting = Formatting::None, int tabc = 0) const; /** * @brief Get the document in the form of a specific type. * @return T The document in the form of a specific type */ - template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { - if (std::is_same::value) { + template T get(const Formatting formatting = Formatting::None, int tabc = 0) const { + if (std::is_same_v) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); @@ -1129,7 +1161,7 @@ namespace docpp { * @brief Get the section * @return Section The section */ - Section get_section() const; + [[nodiscard]] Section get_section() const; /** * @brief Get the section * @return Section The section @@ -1139,13 +1171,13 @@ namespace docpp { * @brief Get the doctype of the document * @return std::string The doctype of the document */ - std::string get_doctype() const; + [[nodiscard]] std::string get_doctype() const; /** * @brief Get the doctype of the document in a specific type * @return T The doctype of the document */ template T get_doctype() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->doctype; } return T(this->doctype); @@ -1165,11 +1197,11 @@ namespace docpp { * @brief Get the size of the document * @return size_type The size of the document */ - size_type size() const; + [[nodiscard]] size_type size() const; /** * @brief Check if the document is empty */ - bool empty() const; + [[nodiscard]] bool empty() const; /** * @brief Clear the document */ @@ -1184,14 +1216,15 @@ namespace docpp { ~Document() = default; /** * @brief Construct a new Document object - * @param document The document to set + * @param document The section to be assigned to the document + * @param doctype The doctype to prepend at the top, before the section */ - Document(const Section& document, const std::string& doctype = "") : document(document), doctype(doctype) {}; + explicit Document(const Section& document, std::string doctype = "") : document(document), doctype(std::move(doctype)) {}; /** * @brief Construct a new Document object * @param document The document to set */ - Document(const Document& document) : document(document.document), doctype(document.doctype) {}; + Document(const Document& document) = default; Document& operator=(const Document& document); Document& operator=(const Section& section); @@ -1200,6 +1233,8 @@ namespace docpp { bool operator!=(const Document& document) const; bool operator!=(const Section& section) const; }; + + template Properties make_properties(Args&&... args) { return Properties(std::forward(args)...); } } // namespace HTML /** @@ -1227,7 +1262,7 @@ namespace docpp { /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Construct a new Property object @@ -1238,7 +1273,7 @@ namespace docpp { /** * @brief Construct a new Property object */ - Property(const Property& property) : property(property.property) {}; + Property(const Property& property) = default; /** * @brief Construct a new Property object */ @@ -1252,13 +1287,13 @@ namespace docpp { * @brief Get the key of the property * @return std::string The key of the property */ - std::string get_key() const; + [[nodiscard]] std::string get_key() const; /** * @brief Get the key of the property in a specific type * @return T The key of the property */ template T get_key() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->property.first; } return T(this->property.first); @@ -1267,13 +1302,13 @@ namespace docpp { * @brief Get the value of the property * @return std::string The value of the property */ - std::string get_value() const; + [[nodiscard]] std::string get_value() const; /** * @brief Get the value of the property in a specific type * @return T The value of the property */ template T get_value() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->property.second; } return T(this->property.second); @@ -1282,13 +1317,13 @@ namespace docpp { * @brief Get the property. * @return std::pair The value of the property */ - std::pair get() const; + [[nodiscard]] std::pair get() const; /** * @brief Get the property in a specific type. * @return std::pair The value of the property */ template std::pair get() const { - if (std::is_same::value) { + if (std::is_same_v) { return std::make_pair(this->property.first, this->property.second); } return std::pair(this->property.first, this->property.second); @@ -1339,16 +1374,26 @@ namespace docpp { * @return iterator The iterator to the end. */ iterator end() { return element.second.end(); } + /** + * @brief Return a const_iterator to the beginning. + * @return const_iterator The const_iterator to the beginning. + */ + [[nodiscard]] const_iterator begin() const { return element.second.begin(); } + /** + * @brief Return a const_iterator to the end. + * @return const_iterator The const_iterator to the end. + */ + [[nodiscard]] const_iterator end() const { return element.second.end(); } /** * @brief Return a const iterator to the beginning. * @return const_iterator The const iterator to the beginning. */ - const_iterator cbegin() const { return element.second.cbegin(); } + [[nodiscard]] const_iterator cbegin() const { return element.second.cbegin(); } /** * @brief Return a const iterator to the end. * @return const_iterator The const iterator to the end. */ - const_iterator cend() const { return element.second.cend(); } + [[nodiscard]] const_iterator cend() const { return element.second.cend(); } /** * @brief Return a reverse iterator to the beginning. * @return reverse_iterator The reverse iterator to the beginning. @@ -1363,17 +1408,17 @@ namespace docpp { * @brief Return a const reverse iterator to the beginning. * @return const_reverse_iterator The const reverse iterator to the beginning. */ - const_reverse_iterator crbegin() { return element.second.crbegin(); } + [[nodiscard]] const_reverse_iterator crbegin() const { return element.second.crbegin(); } /** * @brief Return a const reverse iterator to the end. * @return const_reverse_iterator The const reverse iterator to the end. */ - const_reverse_iterator crend() { return element.second.crend(); } + [[nodiscard]] const_reverse_iterator crend() const { return element.second.crend(); } /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Construct a new Element object @@ -1385,7 +1430,7 @@ namespace docpp { * @brief Construct a new Element object * @param element The element to set */ - Element(const Element& element) : element(element.element) {}; + Element(const Element& element) = default; /** * @brief Construct a new Element object */ @@ -1410,42 +1455,42 @@ namespace docpp { * @param index The index to insert the property * @param property The property to insert */ - void insert(const size_type index, const Property& property); + void insert(size_type index, const Property& property); /** * @brief Erase a property from the element * @param index The index of the property to erase */ - void erase(const size_type index); + void erase(size_type index); /** * @brief Find a property in the element * @param property The property to find * @return size_type The index of the property */ - size_type find(const Property& property); + [[nodiscard]] size_type find(const Property& property) const; /** * @brief Get the property at an index * @param index The index of the property * @return Property The property at the index */ - Property at(const size_type index) const; + [[nodiscard]] Property at(size_type index) const; /** * @brief Get the property at an index * @param index The index of the property * @return Property The property at the index */ - Property& at(const size_type index); + Property& at(size_type index); /** * @brief Find a property in the element * @param str The property to find * @return size_type The index of the property */ - size_type find(const std::string& str); + [[nodiscard]] size_type find(const std::string& str) const; /** * @brief Swap two properties in the element * @param index1 The index of the first property * @param index2 The index of the second property */ - void swap(const size_type index1, const size_type index2); + void swap(size_type index1, size_type index2); /** * @brief Swap two properties in the element * @param property1 The first property @@ -1456,7 +1501,7 @@ namespace docpp { * @brief Get the first property of the element * @return Property The first property of the element */ - Property front() const; + [[nodiscard]] Property front() const; /** * @brief Get the first property of the element * @return Property The first property of the element @@ -1466,7 +1511,7 @@ namespace docpp { * @brief Get the last property of the element * @return Property The last property of the element */ - Property back() const; + [[nodiscard]] Property back() const; /** * @brief Get the last property of the element * @return Property The last property of the element @@ -1476,7 +1521,7 @@ namespace docpp { * @brief Get the size of the element * @return size_type The size of the element */ - size_type size() const; + [[nodiscard]] size_type size() const; /** * @brief Clear the element */ @@ -1485,7 +1530,7 @@ namespace docpp { * @brief Check if the element is empty * @return bool True if the element is empty, false otherwise */ - bool empty() const; + [[nodiscard]] bool empty() const; /** * @brief Set the properties of the element * @param tag The tag of the element @@ -1497,7 +1542,7 @@ namespace docpp { * @param tag The tag of the element * @param properties The properties to set */ - void set(const HTML::Tag tag, const std::vector& properties); + void set(HTML::Tag tag, const std::vector& properties); /** * @brief Set the tag of the element * @param tag The tag to set @@ -1507,7 +1552,7 @@ namespace docpp { * @brief Set the tag of the element * @param tag The tag to set */ - void set_tag(const HTML::Tag tag); + void set_tag(HTML::Tag tag); /** * @brief Set the properties of the element * @param properties The properties to set @@ -1517,13 +1562,13 @@ namespace docpp { * @brief Get the element * @return std::pair> The element */ - std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; + [[nodiscard]] std::string get(Formatting formatting = Formatting::None, int tabc = 0) const; /** * @brief Get the element in the form of a specific type. * @return T The element in the form of a specific type */ template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { - if (std::is_same::value) { + if (std::is_same_v) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); @@ -1532,13 +1577,13 @@ namespace docpp { * @brief Get the tag of the element * @return std::string The tag of the element */ - std::string get_tag() const; + [[nodiscard]] std::string get_tag() const; /** * @brief Get the tag of the element in a specific type * @return T The tag of the element */ template T get_tag() const { - if (std::is_same::value) { + if (std::is_same_v) { return this->element.first; } return T(this->element.first); @@ -1547,7 +1592,7 @@ namespace docpp { * @brief Get the properties of the element * @return std::vector The properties of the element */ - std::vector get_properties() const; + [[nodiscard]] std::vector get_properties() const; Element& operator=(const Element& element); Element& operator=(const std::pair>& element); @@ -1581,16 +1626,26 @@ namespace docpp { * @return iterator The iterator to the end. */ iterator end() { return elements.end(); } + /** + * @brief Return a const_iterator to the beginning. + * @return const_iterator The iterator to the beginning. + */ + [[nodiscard]] const_iterator begin() const { return elements.begin(); } + /** + * @brief Return a const_iterator to the end. + * @return const_iterator The iterator to the end. + */ + [[nodiscard]] const_iterator end() const { return elements.end(); } /** * @brief Return a const iterator to the beginning. * @return const_iterator The const iterator to the beginning. */ - const_iterator cbegin() const { return elements.cbegin(); } + [[nodiscard]] const_iterator cbegin() const { return elements.cbegin(); } /** * @brief Return a const iterator to the end. * @return const_iterator The const iterator to the end. */ - const_iterator cend() const { return elements.cend(); } + [[nodiscard]] const_iterator cend() const { return elements.cend(); } /** * @brief Return a reverse iterator to the beginning. * @return reverse_iterator The reverse iterator to the beginning. @@ -1605,28 +1660,28 @@ namespace docpp { * @brief Return a const reverse iterator to the beginning. * @return const_reverse_iterator The const reverse iterator to the beginning. */ - const_reverse_iterator crbegin() { return elements.crbegin(); } + [[nodiscard]] const_reverse_iterator crbegin() const { return elements.crbegin(); } /** * @brief Return a const reverse iterator to the end. * @return const_reverse_iterator The const reverse iterator to the end. */ - const_reverse_iterator crend() { return elements.crend(); } + [[nodiscard]] const_reverse_iterator crend() const { return elements.crend(); } /** * @brief The npos value */ - static const size_type npos = -1; + static constexpr size_type npos = -1; /** * @brief Construct a new Stylesheet object - * @param elements The elements to set */ + template explicit Stylesheet(Args... args) { (this->push_back(args), ...); } explicit Stylesheet(const std::vector& elements) : elements(elements) {}; /** * @brief Construct a new Stylesheet object * @param stylesheet The stylesheet to set */ - Stylesheet(const Stylesheet& stylesheet) : elements(stylesheet.elements) {}; + Stylesheet(const Stylesheet& stylesheet) = default; /** * @brief Construct a new Stylesheet object */ @@ -1651,35 +1706,35 @@ namespace docpp { * @param index The index to insert the element * @param element The element to insert */ - void insert(const size_type index, const Element& element); + void insert(size_type index, const Element& element); /** * @brief Erase an element from the stylesheet. Note that this will NOT change the size/index. * @param index The index of the element to erase */ - void erase(const size_type index); + void erase(size_type index); /** * @brief Find an element in the stylesheet * @param element The element to find * @return size_type The index of the element */ - size_type find(const Element& element); + [[nodiscard]] size_type find(const Element& element) const; /** * @brief Find an element in the stylesheet * @param str The element to find, either the tag or the stylesheet itself * @return size_type The index of the element */ - size_type find(const std::string& str); + [[nodiscard]] size_type find(const std::string& str) const; /** * @brief Get the element at an index * @param index The index of the element * @return Element The element at the index */ - Element at(const size_type index) const; + [[nodiscard]] Element at(size_type index) const; /** * @brief Get the size of the stylesheet * @return size_type The size of the stylesheet */ - size_type size() const; + [[nodiscard]] size_type size() const; /** * @brief Clear the stylesheet */ @@ -1688,23 +1743,23 @@ namespace docpp { * @brief Check if the stylesheet is empty * @return bool True if the stylesheet is empty, false otherwise */ - bool empty() const; + [[nodiscard]] bool empty() const; /** * @brief Get the first element of the stylesheet * @return Element The first element of the stylesheet */ - Element front() const; + [[nodiscard]] Element front() const; /** * @brief Get the last element of the stylesheet * @return Element The last element of the stylesheet */ - Element back() const; + [[nodiscard]] Element back() const; /** * @brief Swap two elements in the stylesheet * @param index1 The index of the first element * @param index2 The index of the second element */ - void swap(const size_type index1, const size_type index2); + void swap(size_type index1, size_type index2); /** * @brief Swap two elements in the stylesheet * @param element1 The first element @@ -1720,18 +1775,18 @@ namespace docpp { * @brief Get the elements of the stylesheet * @return std::vector The elements of the stylesheet */ - std::vector get_elements() const; + [[nodiscard]] std::vector get_elements() const; /** * @brief Get the stylesheet * @return std::string The stylesheet */ - std::string get(const Formatting formatting = Formatting::None, const int tabc = 0) const; + [[nodiscard]] std::string get(Formatting formatting = Formatting::None, int tabc = 0) const; /** * @brief Get the stylesheet in the form of a specific type. * @return T The stylesheet in the form of a specific type */ template T get(const Formatting formatting = Formatting::None, const int tabc = 0) const { - if (std::is_same::value) { + if (std::is_same_v) { return this->get(formatting, tabc); } return T(this->get(formatting, tabc)); @@ -1743,6 +1798,8 @@ namespace docpp { bool operator==(const Stylesheet& stylesheet) const; bool operator!=(const Stylesheet& stylesheet) const; }; + + template Stylesheet make_stylesheet(Args&&... args) { return Stylesheet(std::forward(args)...); } } // namespace CSS /** diff --git a/src/docpp.cpp b/src/docpp.cpp index d69a6a2..be9cf11 100644 --- a/src/docpp.cpp +++ b/src/docpp.cpp @@ -79,13 +79,10 @@ bool docpp::HTML::Properties::operator==(const docpp::HTML::Properties& properti } bool docpp::HTML::Properties::operator==(const docpp::HTML::Property& property) const { - for (const docpp::HTML::Property& it : this->properties) { - if (it.get() == property.get()) { - return true; - } - } - - return false; + return std::any_of(this->properties.begin(), this->properties.end(), + [&property](const docpp::HTML::Property& it) { + return it.get() == property.get(); + }); } bool docpp::HTML::Properties::operator!=(const docpp::HTML::Properties& properties) const { @@ -93,13 +90,9 @@ bool docpp::HTML::Properties::operator!=(const docpp::HTML::Properties& properti } bool docpp::HTML::Properties::operator!=(const docpp::HTML::Property& property) const { - for (const docpp::HTML::Property& it : this->properties) { - if (it.get() == property.get()) { - return false; - } - } - - return true; + return std::all_of(this->properties.begin(), this->properties.end(), [&property](const docpp::HTML::Property& it) { + return it.get() == property.get(); + }); } docpp::HTML::Properties& docpp::HTML::Properties::operator+=(const docpp::HTML::Property& property) { @@ -108,8 +101,8 @@ docpp::HTML::Properties& docpp::HTML::Properties::operator+=(const docpp::HTML:: } docpp::HTML::Properties& docpp::HTML::Properties::operator+=(const docpp::HTML::Properties& properties) { - for (docpp::HTML::Properties::const_iterator it{properties.cbegin()}; it != properties.cend(); it++) { - this->push_back(*it); + for (const docpp::HTML::Property& it : properties) { + this->push_back(it); } return *this; @@ -120,7 +113,7 @@ std::vector docpp::HTML::Properties::get_properties() con } docpp::HTML::Property docpp::HTML::Properties::at(const size_type index) const { - if (index < 0 || index >= this->properties.size()) { + if (index >= this->properties.size()) { throw docpp::out_of_range("Index out of range"); } @@ -132,19 +125,19 @@ void docpp::HTML::Properties::set(const std::vector& prop } void docpp::HTML::Properties::insert(const size_type index, const docpp::HTML::Property& property) { - if (index < 0 || index >= this->properties.size()) { + if (index >= this->properties.size()) { throw docpp::out_of_range("Index out of range"); } - this->properties.insert(this->properties.begin() + index, property); + this->properties.insert(this->properties.begin() + static_cast(index), property); } void docpp::HTML::Properties::erase(const size_type index) { - if (index < 0 || index >= this->properties.size()) { + if (index >= this->properties.size()) { throw docpp::out_of_range("Index out of range"); } - this->properties.erase(this->properties.begin() + index); + this->properties.erase(this->properties.begin() + static_cast(index)); } void docpp::HTML::Properties::push_front(const docpp::HTML::Property& property) { @@ -155,17 +148,10 @@ void docpp::HTML::Properties::push_back(const docpp::HTML::Property& property) { this->properties.push_back(property); } -docpp::HTML::Properties::size_type docpp::HTML::Properties::find(const docpp::HTML::Property& property) { +docpp::HTML::Properties::size_type docpp::HTML::Properties::find(const docpp::HTML::Property& property) const { for (size_type i{0}; i < this->properties.size(); i++) { - if (!this->properties.at(i).get_key().compare(property.get_key())) { - return i; - } else if (!this->properties.at(i).get_value().compare(property.get_value())) { - return i; - } else if (this->properties.at(i).get_value().find(property.get_value()) != std::string::npos) { - return i; - } else if (this->properties.at(i).get_key().find(property.get_key()) != std::string::npos) { - return i; - } else if (this->properties.at(i).get() == property.get()) { + if (this->properties.at(i).get_value().find(property.get_value()) != std::string::npos + || this->properties.at(i).get_key().find(property.get_key()) != std::string::npos) { return i; } } @@ -173,11 +159,10 @@ docpp::HTML::Properties::size_type docpp::HTML::Properties::find(const docpp::HT return docpp::HTML::Properties::npos; } -docpp::HTML::Properties::size_type docpp::HTML::Properties::find(const std::string& str) { +docpp::HTML::Properties::size_type docpp::HTML::Properties::find(const std::string& str) const { for (size_type i{0}; i < this->properties.size(); i++) { - if (!this->properties.at(i).get_key().compare(str) || !this->properties.at(i).get_value().compare(str)) { - return i; - } else if (this->properties.at(i).get_key().find(str) != std::string::npos || this->properties.at(i).get_value().find(str) != std::string::npos) { + if (this->properties.at(i).get_key().find(str) != std::string::npos || + this->properties.at(i).get_value().find(str) != std::string::npos) { return i; } } @@ -206,7 +191,7 @@ bool docpp::HTML::Properties::empty() const { } void docpp::HTML::Properties::swap(const size_type index1, const size_type index2) { - if (index1 < 0 || index1 >= this->properties.size() || index2 < 0 || index2 >= this->properties.size()) { + if (index1 >= this->properties.size() || index2 >= this->properties.size()) { throw docpp::out_of_range("Index out of range"); } @@ -297,8 +282,9 @@ std::string docpp::HTML::Element::get(const Formatting formatting, const int tab } for (const Property& it : this->properties.get_properties()) { - if (!it.get_key().compare("")) continue; - if (!it.get_value().compare("")) continue; + if (it.get_key().empty() || it.get_value().empty()) { + continue; + } ret += " " + it.get_key() + "=\"" + it.get_value() + "\""; } @@ -348,15 +334,7 @@ void docpp::HTML::Element::clear() { this->properties.clear(); } -docpp::HTML::Section& docpp::HTML::Section::operator=(const docpp::HTML::Section& section) { - this->tag = section.tag; - this->properties = section.properties; - this->elements = section.elements; - this->sections = section.sections; - this->index = section.index; - - return *this; -} +docpp::HTML::Section& docpp::HTML::Section::operator=(const docpp::HTML::Section& section) = default; docpp::HTML::Section& docpp::HTML::Section::operator+=(const docpp::HTML::Element& element) { this->push_back(element); @@ -376,7 +354,7 @@ std::unordered_map docpp::HTML::Section::oper std::unordered_map ret{}; for (const Element& it : this->get_elements()) { - if (!it.get_tag().compare(tag)) { + if (it.get_tag() == tag) { ret[it.get_data()] = it; } } @@ -388,7 +366,7 @@ std::unordered_map docpp::HTML::Section::oper std::unordered_map ret{}; for (const Element& it : this->get_elements()) { - if (!it.get_tag().compare(resolve_tag(tag).first)) { + if (it.get_tag() == resolve_tag(tag).first) { ret[it.get_data()] = it; } } @@ -401,13 +379,10 @@ bool docpp::HTML::Section::operator==(const docpp::HTML::Section& section) const } bool docpp::HTML::Section::operator==(const docpp::HTML::Element& element) const { - for (const Element& it : this->get_elements()) { - if (it.get() == element.get()) { - return true; - } - } - - return false; + return std::any_of(this->get_elements().begin(), this->get_elements().end(), + [&element](const docpp::HTML::Element& it) { + return it.get() == element.get(); + }); } bool docpp::HTML::Section::operator!=(const docpp::HTML::Section& section) const { @@ -415,13 +390,9 @@ bool docpp::HTML::Section::operator!=(const docpp::HTML::Section& section) const } bool docpp::HTML::Section::operator!=(const docpp::HTML::Element& element) const { - for (const Element& it : this->get_elements()) { - if (it.get() == element.get()) { - return false; - } - } - - return true; + return std::any_of(this->get_elements().begin(), this->get_elements().end(), [&element](const Element& it) { + return it.get() == element.get(); + }); } void docpp::HTML::Section::set(const std::string& tag, const Properties& properties) { @@ -606,8 +577,8 @@ std::pair docpp::HTML::resolve_tag(const Tag tag docpp::HTML::Tag docpp::HTML::resolve_tag(const std::string& tag) { const std::unordered_map> tag_map{get_tag_map()}; - for (const std::pair>& it : tag_map) { - if (!it.second.first.compare(tag)) { + for (const auto& it : tag_map) { + if (it.second.first == tag) { return it.first; } } @@ -735,7 +706,7 @@ docpp::HTML::Section& docpp::HTML::Section::at_section(const size_type index) { throw docpp::out_of_range("Index out of range"); } -docpp::HTML::Section::size_type docpp::HTML::Section::find(const Element& element) { +docpp::HTML::Section::size_type docpp::HTML::Section::find(const Element& element) const { for (size_type i{0}; i < this->size(); i++) { const Element it = this->get_elements().at(i); @@ -747,7 +718,7 @@ docpp::HTML::Section::size_type docpp::HTML::Section::find(const Element& elemen return docpp::HTML::Section::npos; } -docpp::HTML::Section::size_type docpp::HTML::Section::find(const Section& section) { +docpp::HTML::Section::size_type docpp::HTML::Section::find(const Section& section) const { for (size_type i{0}; i < this->size(); i++) { const Section it = this->get_sections().at(i); @@ -759,7 +730,7 @@ docpp::HTML::Section::size_type docpp::HTML::Section::find(const Section& sectio return docpp::HTML::Section::npos; } -docpp::HTML::Section::size_type docpp::HTML::Section::find(const std::string& str) { +docpp::HTML::Section::size_type docpp::HTML::Section::find(const std::string& str) const { const std::vector elements{this->get_elements()}; for (size_type i{0}; i < this->size(); i++) { @@ -891,31 +862,29 @@ std::vector docpp::HTML::Section::get_sections() const { return ret; } -std::string docpp::HTML::Section::get(const Formatting formatting, const int tabc) const { +std::string docpp::HTML::Section::get(const Formatting formatting, const int tabc) const { // NOLINT std::string ret{}; int tabcount{tabc}; - if (!this->tag.compare("")) { - --tabcount; // i guess this means the section only contains elements and sections, and isn't a tag itself + if (this->tag.empty() && this->properties.empty() && this->sections.empty() && this->elements.empty()) { + return {}; + } - if (tabcount < -1) { - tabcount = -1; // will be incremented by 1, so it will be 0 - } + if (this->tag.empty() && tabcount-1 >= -1) { + --tabcount; // prevent an indent when there's no tag for the section itself (i.e. the section is only a container) } if (formatting == docpp::HTML::Formatting::Pretty) { - for (size_type i{0}; i < tabcount; i++) { - ret += "\t"; - } + for (size_type i{0}; i < tabcount; i++) ret += "\t"; } - if (this->tag.compare("")) { + if (!this->tag.empty()) { ret += "<" + this->tag; for (const Property& it : this->properties.get_properties()) { - if (!it.get_key().compare("")) continue; - if (!it.get_value().compare("")) continue; - + if (it.get_key().empty() || it.get_value().empty()) { + continue; + } ret += " " + it.get_key() + "=\"" + it.get_value() + "\""; } @@ -930,7 +899,11 @@ std::string docpp::HTML::Section::get(const Formatting formatting, const int tab if (this->elements.find(i) != this->elements.end()) { ret += this->elements.at(i).get(formatting, tabcount + 1); } else if (this->sections.find(i) != this->sections.end()) { - ret += this->sections.at(i).get(formatting, tabcount + 1); + const Section* sect_ptr = &this->sections.at(i); + if (this == sect_ptr) { + throw docpp::invalid_argument{"get() cannot be called on this"}; + } + ret += sect_ptr->get(formatting, tabcount + 1); if (formatting == docpp::HTML::Formatting::Pretty || formatting == docpp::HTML::Formatting::Newline) { ret += "\n"; @@ -944,7 +917,7 @@ std::string docpp::HTML::Section::get(const Formatting formatting, const int tab } } - ret += this->tag.compare("") ? ("tag + ">") : ""; + ret += !this->tag.empty() ? ("tag + ">") : ""; return ret; } @@ -1009,7 +982,7 @@ bool docpp::HTML::Document::empty() const { } docpp::HTML::Document& docpp::HTML::Document::operator=(const docpp::HTML::Document& document) { - this->set(document.get()); + this->set(document.get_section()); this->set_doctype(document.get_doctype()); return *this; } @@ -1124,23 +1097,23 @@ void docpp::CSS::Element::push_back(const Property& property) { } void docpp::CSS::Element::insert(const size_type index, const Property& property) { - if (index < 0 || index >= this->element.second.size()) { + if (index >= this->element.second.size()) { throw docpp::out_of_range("Index out of range"); } - this->element.second.insert(this->element.second.begin() + index, property); + this->element.second.insert(this->element.second.begin() + static_cast(index), property); } void docpp::CSS::Element::erase(const size_type index) { - if (index < 0 || index >= this->element.second.size()) { + if (index >= this->element.second.size()) { throw docpp::out_of_range("Index out of range"); } - this->element.second.erase(this->element.second.begin() + index); + this->element.second.erase(this->element.second.begin() + static_cast(index)); } docpp::CSS::Property docpp::CSS::Element::at(const size_type index) const { - if (index < 0 || index >= this->element.second.size()) { + if (index >= this->element.second.size()) { throw docpp::out_of_range("Index out of range"); } @@ -1148,14 +1121,14 @@ docpp::CSS::Property docpp::CSS::Element::at(const size_type index) const { } docpp::CSS::Property& docpp::CSS::Element::at(const size_type index) { - if (index < 0 || index >= this->element.second.size()) { + if (index >= this->element.second.size()) { throw docpp::out_of_range("Index out of range"); } return this->element.second.at(index); } -docpp::CSS::Element::size_type docpp::CSS::Element::find(const Property& property) { +docpp::CSS::Element::size_type docpp::CSS::Element::find(const Property& property) const { for (size_type i{0}; i < this->element.second.size(); i++) { if (this->element.second.at(i).get() == property.get()) { return i; @@ -1165,9 +1138,9 @@ docpp::CSS::Element::size_type docpp::CSS::Element::find(const Property& propert return docpp::CSS::Element::npos; } -docpp::CSS::Element::size_type docpp::CSS::Element::find(const std::string& str) { +docpp::CSS::Element::size_type docpp::CSS::Element::find(const std::string& str) const { for (size_type i{0}; i < this->element.second.size(); i++) { - if (!this->element.second.at(i).get_key().compare(str) || !this->element.second.at(i).get_value().compare(str)) { + if (this->element.second.at(i).get_key() == str || this->element.second.at(i).get_value() == str) { return i; } } @@ -1205,7 +1178,7 @@ void docpp::CSS::Element::clear() { } void docpp::CSS::Element::swap(const size_type index1, const size_type index2) { - if (index1 < 0 || index1 >= this->element.second.size() || index2 < 0 || index2 >= this->element.second.size()) { + if (index1 >= this->element.second.size() || index2 >= this->element.second.size()) { throw docpp::out_of_range("Index out of range"); } @@ -1219,7 +1192,7 @@ void docpp::CSS::Element::swap(const Property& property1, const Property& proper std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc) const { std::string ret{}; - if (this->element.first.compare("")) { + if (!this->element.first.empty()) { if (formatting == docpp::CSS::Formatting::Pretty) { for (size_type i{0}; i < tabc; i++) { ret += "\t"; @@ -1233,8 +1206,9 @@ std::string docpp::CSS::Element::get(const Formatting formatting, const int tabc } for (const Property& it : this->element.second) { - if (!it.get_key().compare("")) continue; - if (!it.get_value().compare("")) continue; + if (it.get_key().empty() || it.get_value().empty()) { + continue; + } if (formatting == docpp::CSS::Formatting::Pretty) { for (size_type i{0}; i < tabc + 1; i++) { @@ -1286,19 +1260,19 @@ void docpp::CSS::Stylesheet::push_back(const Element& element) { } void docpp::CSS::Stylesheet::insert(const size_type index, const Element& element) { - if (index < 0 || index >= this->elements.size()) { + if (index >= this->elements.size()) { throw docpp::out_of_range("Index out of range"); } - this->elements.insert(this->elements.begin() + index, element); + this->elements.insert(this->elements.begin() + static_cast(index), element); } void docpp::CSS::Stylesheet::erase(const size_type index) { - if (index < 0 || index >= this->elements.size()) { + if (index >= this->elements.size()) { throw docpp::out_of_range("Index out of range"); } - this->elements.erase(this->elements.begin() + index); + this->elements.erase(this->elements.begin() + static_cast(index)); } docpp::CSS::Stylesheet& docpp::CSS::Stylesheet::operator=(const docpp::CSS::Stylesheet& stylesheet) { @@ -1324,14 +1298,14 @@ bool docpp::CSS::Stylesheet::operator!=(const docpp::CSS::Stylesheet& stylesheet } docpp::CSS::Element docpp::CSS::Stylesheet::at(const size_type index) const { - if (index < 0 || index >= this->elements.size()) { + if (index >= this->elements.size()) { throw docpp::out_of_range("Index out of range"); } return this->elements.at(index); } -docpp::CSS::Stylesheet::size_type docpp::CSS::Stylesheet::find(const Element& element) { +docpp::CSS::Stylesheet::size_type docpp::CSS::Stylesheet::find(const Element& element) const { for (size_type i{0}; i < this->elements.size(); i++) { if (this->elements.at(i).get() == element.get()) { return i; @@ -1341,9 +1315,9 @@ docpp::CSS::Stylesheet::size_type docpp::CSS::Stylesheet::find(const Element& el return docpp::CSS::Stylesheet::npos; } -docpp::CSS::Stylesheet::size_type docpp::CSS::Stylesheet::find(const std::string& str) { +docpp::CSS::Stylesheet::size_type docpp::CSS::Stylesheet::find(const std::string& str) const { for (size_type i{0}; i < this->elements.size(); i++) { - if (!this->elements.at(i).get().compare(str) || !this->elements.at(i).get_tag().compare(str)) { + if (this->elements.at(i).get() == str || this->elements.at(i).get_tag() == str) { return i; } } @@ -1372,7 +1346,7 @@ docpp::CSS::Element docpp::CSS::Stylesheet::back() const { } void docpp::CSS::Stylesheet::swap(const size_type index1, const size_type index2) { - if (index1 < 0 || index1 >= this->elements.size() || index2 < 0 || index2 >= this->elements.size()) { + if (index1 >= this->elements.size() || index2 >= this->elements.size()) { throw docpp::out_of_range("Index out of range"); } diff --git a/tests/test.cpp b/tests/test.cpp index df3fb87..e6bc490 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -3,6 +3,10 @@ #include #include +// NOLINTBEGIN +// Disable linting. This is a test program and the code is intentionally bad in some places. +// As such, I think it's best to turn linting off rather than to try and resolve any such warnings. + inline namespace HTML { void test_tag() { const auto expected_values = docpp::HTML::get_tag_map(); @@ -17,11 +21,7 @@ inline namespace HTML { using namespace docpp::HTML; Property property; - - REQUIRE(property.get().first == ""); - REQUIRE(property.get().second == ""); - REQUIRE(property.get_key() == ""); - REQUIRE(property.get_value() == ""); + REQUIRE((property.get().first.empty() && property.get().second.empty() && property.get_key().empty() && property.get_value().empty())); property.set({"key", "value"}); @@ -77,7 +77,7 @@ inline namespace HTML { Properties properties; - REQUIRE(properties.size() == 0); + REQUIRE(properties.empty()); properties.push_back({"key1", "value1"}); properties.push_back({"key2", "value2"}); @@ -110,7 +110,7 @@ inline namespace HTML { // should fail, out of range try { - properties.at(3); + static_cast(properties.at(3)); } catch (const docpp::out_of_range& e) { REQUIRE(std::string(e.what()) == "Index out of range"); } @@ -139,10 +139,10 @@ inline namespace HTML { const auto test_iterators = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); std::size_t index{0}; - for (Properties::iterator it = properties.begin(); it != properties.end(); ++it) { + for (auto it = properties.begin(); it != properties.end(); ++it) { if (index == 0) { REQUIRE(it->get().first == "key1"); REQUIRE(it->get().second == "value1"); @@ -158,7 +158,7 @@ inline namespace HTML { } index = 0; - for (Properties::const_iterator it = properties.cbegin(); it != properties.cend(); ++it) { + for (auto it = properties.cbegin(); it != properties.cend(); ++it) { if (index == 0) { REQUIRE(it->get().first == "key1"); REQUIRE(it->get().second == "value1"); @@ -174,7 +174,7 @@ inline namespace HTML { } index = 0; - for (Properties::reverse_iterator it = properties.rbegin(); it != properties.rend(); ++it) { + for (auto it = properties.rbegin(); it != properties.rend(); ++it) { if (index == 0) { REQUIRE(it->get().first == "key3"); REQUIRE(it->get().second == "value3"); @@ -190,7 +190,7 @@ inline namespace HTML { } index = 0; - for (Properties::const_reverse_iterator it = properties.crbegin(); it != properties.crend(); ++it) { + for (auto it = properties.crbegin(); it != properties.crend(); ++it) { if (index == 0) { REQUIRE(it->get().first == "key3"); REQUIRE(it->get().second == "value3"); @@ -225,7 +225,7 @@ inline namespace HTML { const auto test_find = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); REQUIRE(properties.find(Property("key1", "value1")) == 0); REQUIRE(properties.find(Property("key2", "value2")) == 1); @@ -268,7 +268,7 @@ inline namespace HTML { REQUIRE(pos == Properties::npos); try { - properties.at(pos); + static_cast(properties.at(pos)); } catch (const docpp::out_of_range& e) { REQUIRE(std::string(e.what()) == "Index out of range"); } @@ -277,7 +277,7 @@ inline namespace HTML { const auto test_insert = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); std::size_t pos = properties.find("key1"); Property found_property = properties[pos]; @@ -293,7 +293,7 @@ inline namespace HTML { const auto test_swap = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); std::size_t pos1 = properties.find("key1"); Property property1 = properties[pos1]; @@ -315,7 +315,7 @@ inline namespace HTML { const auto test_front_and_back = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); REQUIRE(properties.front().get().first == "key1"); REQUIRE(properties.front().get().second == "value1"); @@ -327,7 +327,7 @@ inline namespace HTML { const auto test_size_empty_and_clear = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); REQUIRE(properties.size() == 3); REQUIRE(properties.empty() == false); @@ -356,19 +356,17 @@ inline namespace HTML { const auto test_constructors = []() { using namespace docpp::HTML; - Properties properties = {{{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}}}; - + Properties properties = make_properties(Property{"key1", "value1"}, Property{"key2", "value2"}, Property{"key3", "value3"}); Properties new_properties = properties; REQUIRE(properties == new_properties); - Properties new_properties2 = properties.get_properties(); + Properties new_properties2(properties.get_properties()); REQUIRE(properties == new_properties2); Property property1{"key1", "value1"}; - - Properties new_properties3 = {property1}; + Properties new_properties3 = make_properties(property1); REQUIRE(new_properties3.size() == 1); }; @@ -514,7 +512,7 @@ inline namespace HTML { REQUIRE(section.get_properties().empty()); section.set_tag("new_section"); - section.set_properties({{Property{"key", "value"}, Property{"key2", "value2"}}}); + section.set_properties(make_properties(Property("key", "value"), Property("key2", "value2"))); REQUIRE(section.get_tag() == "new_section"); REQUIRE(section.get_properties().at(0).get().first == "key"); @@ -522,7 +520,7 @@ inline namespace HTML { REQUIRE(section.get_properties().at(1).get().first == "key2"); REQUIRE(section.get_properties().at(1).get().second == "value2"); - section.set("new_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + section.set("new_section", Properties(Property("key", "value"), Property("key2", "value2"))); REQUIRE(section.get_tag() == "new_section"); REQUIRE(section.get_properties().at(0).get().first == "key"); @@ -530,20 +528,25 @@ inline namespace HTML { REQUIRE(section.get_properties().at(1).get().first == "key2"); REQUIRE(section.get_properties().at(1).get().second == "value2"); - section.set_properties({{Property{"key3", "value3"}, Property{"key4", "value4"}}}); + section.set_properties(make_properties(Property("key3", "value3"), Property("key4", "value4"))); REQUIRE(section.get_properties().at(0).get().first == "key3"); REQUIRE(section.get_properties().at(0).get().second == "value3"); REQUIRE(section.get_properties().at(1).get().first == "key4"); REQUIRE(section.get_properties().at(1).get().second == "value4"); + + Section completely_empty_section; + + static_cast(completely_empty_section.get(docpp::HTML::Formatting::None)); + static_cast(completely_empty_section.get(docpp::HTML::Formatting::Newline)); + static_cast(completely_empty_section.get(docpp::HTML::Formatting::Pretty)); }; const auto test_copy_section = []() { using namespace docpp::HTML; Section section; - - section.set("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + section.set("my_section", make_properties(Property("key", "value"), Property("key2", "value2"))); Section new_section = section; @@ -572,12 +575,12 @@ inline namespace HTML { Section section1; Section section2; - section1.set("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); - section2.set("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + section1.set("my_section", make_properties(Property("key", "value"), Property("key2", "value2"))); + section2.set("my_section", make_properties(Property("key", "value"), Property("key2", "value2"))); REQUIRE(section1 == section2); - section2.set("new_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + section2.set("new_section", make_properties(Property("key", "value"), Property("key2", "value2"))); REQUIRE(section1 != section2); @@ -613,7 +616,7 @@ inline namespace HTML { REQUIRE(section.get_elements().empty()); REQUIRE(section.get_properties().empty()); - Section section2("my_section", {{Property{"key", "value"}, Property{"key2", "value2"}}}); + Section section2("my_section", make_properties(Property("key", "value"), Property("key2", "value2"))); REQUIRE(section2.get_tag() == "my_section"); REQUIRE(section2.get_properties().at(0).get().first == "key"); @@ -621,7 +624,7 @@ inline namespace HTML { REQUIRE(section2.get_properties().at(1).get().first == "key2"); REQUIRE(section2.get_properties().at(1).get().second == "value2"); - Section section3(docpp::HTML::Tag::H1, {{Property{"key", "value"}, Property{"key2", "value2"}}}); + Section section3(docpp::HTML::Tag::H1, make_properties(Property{"key", "value"}, Property{"key2", "value2"}), {Element{}}); REQUIRE(section3.get_tag() == "h1"); REQUIRE(section3.get_properties().at(0).get().first == "key"); @@ -644,7 +647,7 @@ inline namespace HTML { Element element; std::size_t index{0}; - for (Section::iterator it = section.begin(); it != section.end(); ++it) { + for (auto it = section.begin(); it != section.end(); ++it) { Element element = *it; if (index == 0) { @@ -1594,7 +1597,7 @@ inline namespace CSS { REQUIRE(stylesheet.at(0).get_properties().at(1).get().second == "value4"); try { - stylesheet.at(1); + static_cast(stylesheet.at(1)); } catch (const docpp::out_of_range& e) { REQUIRE(true); } @@ -1918,3 +1921,5 @@ SCENARIO("Test HTML", "[HTML]") { SCENARIO("Test CSS", "[CSS]") { CSS::test_css(); } + +// NOLINTEND \ No newline at end of file