// Copyright (c) 2010, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /// @file line_iterator.h /// @brief An iterator over lines in a stream /// @ingroup libaegisub #pragma once #include #include #include #include namespace agi { namespace charset { class IconvWrapper; } class line_iterator_base { std::istream *stream = nullptr; ///< Stream to iterate over std::shared_ptr conv; int cr = '\r'; ///< CR character in the source encoding int lf = '\n'; ///< LF character in the source encoding size_t width = 1; ///< width of LF character in the source encoding protected: bool getline(std::string &str); public: line_iterator_base(std::istream &stream, std::string encoding = "utf-8"); line_iterator_base() = default; line_iterator_base(line_iterator_base const&) = default; #ifndef _MSC_VER line_iterator_base(line_iterator_base&&) = default; #endif line_iterator_base& operator=(line_iterator_base const&) = default; #ifndef _MSC_VER line_iterator_base& operator=(line_iterator_base&&) = default; #endif bool operator==(line_iterator_base const& rgt) const { return stream == rgt.stream; } bool operator!=(line_iterator_base const& rgt) const { return !operator==(rgt); } }; /// @class line_iterator /// @brief An iterator over lines in a stream template class line_iterator final : public line_iterator_base, public std::iterator { OutputType value; ///< Value to return when this is dereference /// @brief Convert a string to the output type /// @param str Line read from the file /// /// line_iterator users can either ensure that operator>> is defined for /// their desired output type or simply provide a specialization of this /// method which does the conversion. inline bool convert(std::string &str); /// @brief Get the next value from the stream void next(); public: /// @brief Constructor /// @param stream The stream to read from. The calling code is responsible /// for ensuring that the stream remains valid for the /// lifetime of the iterator and that it get cleaned up. /// @param encoding Encoding of the text read from the stream line_iterator(std::istream &stream, std::string encoding = "utf-8") : line_iterator_base(stream, std::move(encoding)) { ++(*this); } /// @brief Invalid iterator constructor; use for end iterator line_iterator() = default; /// @brief Copy constructor /// @param that line_iterator to copy from line_iterator(line_iterator const&) = default; OutputType const& operator*() const { return value; } OutputType const* operator->() const { return &value; } line_iterator& operator++() { next(); return *this; } line_iterator operator++(int) { line_iterator tmp(*this); ++*this; return tmp; } // typedefs needed by some stl algorithms typedef OutputType* pointer; typedef OutputType& reference; typedef const OutputType* const_pointer; typedef const OutputType& const_reference; }; // Enable range-based for template line_iterator& begin(line_iterator& it) { return it; } template line_iterator end(line_iterator&) { return agi::line_iterator(); } template void line_iterator::next() { std::string str; if (!getline(str)) return; if (!convert(str)) next(); } template<> inline void line_iterator::next() { value.clear(); getline(value); } template inline bool line_iterator::convert(std::string &str) { boost::interprocess::ibufferstream ss(str.data(), str.size()); ss >> value; return !ss.fail(); } }