Browse Source

LibCore: Add support for range-based for loops on LineIterators

Sahan Fernando 3 years ago
parent
commit
2c43eaa50c

+ 30 - 17
Tests/LibCore/TestLibCoreIODevice.cpp

@@ -8,6 +8,14 @@
 #include <LibTest/TestCase.h>
 #include <unistd.h>
 
+static bool files_have_same_contents(String filename1, String filename2)
+{
+    auto file1 = Core::File::open(filename1, Core::OpenMode::ReadOnly).value();
+    auto file2 = Core::File::open(filename2, Core::OpenMode::ReadOnly).value();
+    auto contents1 = file1->read_all(), contents2 = file2->read_all();
+    return contents1 == contents2;
+}
+
 TEST_CASE(file_readline)
 {
     auto path = "long_lines.txt";
@@ -26,23 +34,7 @@ TEST_CASE(file_readline)
     }
     file->close();
     outputfile->close();
-
-    // Open files again for comparison since otherwise read_all returns empty (even when not closing the file)
-    file = Core::File::construct(path);
-    if (!file->open(Core::OpenMode::ReadOnly))
-        VERIFY_NOT_REACHED();
-    outputfile = Core::File::construct(output_path);
-    if (!outputfile->open(Core::OpenMode::ReadOnly))
-        VERIFY_NOT_REACHED();
-    auto inputData = file->read_all();
-    auto outputData = outputfile->read_all();
-    EXPECT(inputData.size() > 0);
-    EXPECT_EQ(inputData.size(), outputData.size());
-
-    // Compare char by char
-    for (size_t i = 0; i < inputData.size(); i++) {
-        EXPECT_EQ(inputData[i], outputData[i]);
-    }
+    VERIFY(files_have_same_contents(path, output_path));
 }
 
 TEST_CASE(file_get_read_position)
@@ -76,3 +68,24 @@ TEST_CASE(file_get_read_position)
         EXPECT_EQ(offset, 0);
     }
 }
+
+TEST_CASE(file_lines_range)
+{
+    auto path = "long_lines.txt";
+    auto file_or_error = Core::File::open(path, Core::OpenMode::ReadOnly);
+    if (file_or_error.is_error()) {
+        warnln("Failed to open {}: {}", path, file_or_error.error());
+        VERIFY_NOT_REACHED();
+    }
+    auto file = file_or_error.release_value();
+    auto output_path = "/tmp/output.txt";
+    auto outfile_or_error = Core::File::open(output_path, Core::OpenMode::WriteOnly);
+    auto outputfile = outfile_or_error.release_value();
+    for (auto line : file->lines()) {
+        outputfile->write(line);
+        outputfile->write("\n");
+    }
+    file->close();
+    outputfile->close();
+    VERIFY(files_have_same_contents(path, output_path));
+}

+ 4 - 0
Userland/Libraries/LibCore/IODevice.cpp

@@ -319,4 +319,8 @@ LineIterator& LineIterator::operator++()
     m_buffer = m_device->read_line();
     return *this;
 }
+
+LineIterator LineRange::begin() { return m_device.line_begin(); }
+LineIterator LineRange::end() { return m_device.line_end(); }
+
 }

+ 20 - 0
Userland/Libraries/LibCore/IODevice.h

@@ -12,6 +12,8 @@
 
 namespace Core {
 
+class IODevice;
+
 // This is not necessarily a valid iterator in all contexts,
 // if we had concepts, this would be InputIterator, not Copyable, Movable.
 class LineIterator {
@@ -34,6 +36,20 @@ private:
     String m_buffer;
 };
 
+class LineRange {
+public:
+    LineRange() = delete;
+    explicit LineRange(IODevice& device)
+        : m_device(device)
+    {
+    }
+    LineIterator begin();
+    LineIterator end();
+
+private:
+    IODevice& m_device;
+};
+
 enum class OpenMode : unsigned {
     NotOpen = 0,
     ReadOnly = 1,
@@ -91,6 +107,10 @@ public:
 
     LineIterator line_begin() & { return LineIterator(*this); }
     LineIterator line_end() { return LineIterator(*this, true); }
+    LineRange lines()
+    {
+        return LineRange(*this);
+    }
 
 protected:
     explicit IODevice(Object* parent = nullptr);