lib: Reader for segbits files

Acts as an iterator that yields a single record from the file.  Uses a
memory-mapped file and absl::string_view to avoid copies within the
reader.

Signed-off-by: Rick Altherr <kc8apf@kc8apf.net>
Signed-off-by: Tim 'mithro' Ansell <mithro@mithis.com>
This commit is contained in:
Rick Altherr 2017-11-17 22:51:52 -08:00 committed by Tim 'mithro' Ansell
parent 36f429127f
commit 3e203b956b
9 changed files with 223 additions and 1 deletions

View File

@ -1,6 +1,8 @@
add_library(libprjxray
memory_mapped_file.cc)
memory_mapped_file.cc
segbits_file_reader.cc)
target_include_directories(libprjxray PUBLIC "include")
target_link_libraries(libprjxray absl::strings)
if (PRJXRAY_BUILD_TESTING)
add_executable(memory_mapped_file_test memory_mapped_file_test.cc)
@ -8,4 +10,10 @@ if (PRJXRAY_BUILD_TESTING)
add_test(NAME memory_mapped_file_test
COMMAND memory_mapped_file_test
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test_data)
add_executable(segbits_file_reader_test segbits_file_reader_test.cc)
target_link_libraries(segbits_file_reader_test libprjxray gtest_main)
add_test(NAME segbits_file_reader_test
COMMAND segbits_file_reader_test
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test_data)
endif()

View File

@ -0,0 +1,67 @@
#ifndef PRJXRAY_LIB_SEGBITS_FILE_READER_H
#define PRJXRAY_LIB_SEGBITS_FILE_READER_H
#include <iterator>
#include <memory>
#include <absl/strings/string_view.h>
#include <prjxray/memory_mapped_file.h>
namespace prjxray {
class SegbitsFileReader {
public:
class value_type {
public:
absl::string_view tag() const { return tag_; }
absl::string_view bit() const { return bit_; }
private:
friend SegbitsFileReader;
value_type(const absl::string_view &view);
absl::string_view tag_;
absl::string_view bit_;
};
class iterator
: public std::iterator<std::input_iterator_tag, value_type> {
public:
iterator& operator++();
bool operator==(iterator other) const {
return view_ == other.view_; }
bool operator!=(iterator other) const {
return !(*this == other);}
const value_type& operator*() const { return value_; }
const value_type* operator->() const { return &value_; }
protected:
explicit iterator(absl::string_view view)
: view_(view), value_(view) {}
private:
friend SegbitsFileReader;
absl::string_view view_;
value_type value_;
};
static std::unique_ptr<SegbitsFileReader> InitWithFile(
const std::string &path);
iterator begin();
iterator end();
private:
SegbitsFileReader(std::unique_ptr<MemoryMappedFile> &&mapped_file)
: mapped_file_(std::move(mapped_file)) {};
std::unique_ptr<MemoryMappedFile> mapped_file_;
};
} // namespace prjxray
#endif // PRJXRAY_LIB_SEGBITS_FILE_READER_H

View File

@ -0,0 +1,59 @@
#include <prjxray/segbits_file_reader.h>
namespace prjxray {
std::unique_ptr<SegbitsFileReader> SegbitsFileReader::InitWithFile(
const std::string &path) {
auto mapped_file = MemoryMappedFile::InitWithFile(path);
if (!mapped_file) return nullptr;
return std::unique_ptr<SegbitsFileReader>(
new SegbitsFileReader(std::move(mapped_file)));
}
SegbitsFileReader::iterator SegbitsFileReader::begin() {
return iterator(absl::string_view(
static_cast<const char*>(mapped_file_->data()),
mapped_file_->size()));
}
SegbitsFileReader::iterator SegbitsFileReader::end() {
return iterator(absl::string_view());
}
SegbitsFileReader::value_type::value_type(const absl::string_view &view) {
size_t separator_start = view.find_first_of(" \t");
if (separator_start == absl::string_view::npos) {
tag_ = view;
bit_ = absl::string_view();
return;
}
size_t bit_start = view.find_first_not_of(" \t", separator_start);
size_t newline = view.find('\n', bit_start);
if (newline == absl::string_view::npos) {
tag_ = view.substr(0, separator_start);
bit_ = view.substr(bit_start);
return;
}
size_t bit_len = newline - bit_start;
tag_ = view.substr(0, separator_start);
bit_ = view.substr(bit_start, bit_len);
return;
}
SegbitsFileReader::iterator& SegbitsFileReader::iterator::operator++() {
size_t newline = view_.find('\n');
if (newline == absl::string_view::npos) {
view_ = absl::string_view();
}
view_.remove_prefix(newline + 1);
value_ = value_type(view_);
return *this;
}
} // namespace prjxray

View File

@ -0,0 +1,82 @@
#include <prjxray/segbits_file_reader.h>
#include <map>
#include <string>
#include <gtest/gtest.h>
TEST(SegbitsFileReaderTest, NonExistantFileReturnsNull) {
EXPECT_FALSE(prjxray::SegbitsFileReader::InitWithFile("does_not_exist"));
}
TEST(SegbitsFileReaderTest, ZeroLengthFileYieldsNoItems) {
auto segbits_reader =
prjxray::SegbitsFileReader::InitWithFile("empty_file");
ASSERT_TRUE(segbits_reader);
EXPECT_EQ(segbits_reader->begin(), segbits_reader->end());
}
TEST(SegbitsFileReaderTest, FileWithOneEntry) {
auto segbits_reader =
prjxray::SegbitsFileReader::InitWithFile("one_entry.segbits");
ASSERT_TRUE(segbits_reader);
auto begin_iter = segbits_reader->begin();
EXPECT_EQ(begin_iter->tag(), "CLBLL_L.SLICEL_X0.A5FF.ZINI");
EXPECT_EQ(begin_iter->bit(), "31_06");
EXPECT_EQ(++begin_iter, segbits_reader->end());
}
TEST(SegbitsFileReaderTest, FileWithOneEntryWithEmptyTag) {
auto segbits_reader = prjxray::SegbitsFileReader::InitWithFile(
"one_entry_empty_tag.segbits");
ASSERT_TRUE(segbits_reader);
auto begin_iter = segbits_reader->begin();
EXPECT_EQ(begin_iter->tag(), "");
EXPECT_EQ(begin_iter->bit(), "31_06");
EXPECT_EQ(++begin_iter, segbits_reader->end());
}
TEST(SegbitsFileReaderTest, FileWithOneEntryMissingBit) {
auto segbits_reader = prjxray::SegbitsFileReader::InitWithFile(
"one_entry_missing_bit.segbits");
ASSERT_TRUE(segbits_reader);
auto begin_iter = segbits_reader->begin();
EXPECT_EQ(begin_iter->tag(), "CLBLL_L.SLICEL_X0.A5FF.ZINI");
EXPECT_EQ(begin_iter->bit(), "");
EXPECT_EQ(++begin_iter, segbits_reader->end());
}
TEST(SegbitsFileReaderTest, FileWithOneEntryWithExtraWhitespace) {
auto segbits_reader = prjxray::SegbitsFileReader::InitWithFile(
"one_entry_extra_whitespace.segbits");
ASSERT_TRUE(segbits_reader);
auto begin_iter = segbits_reader->begin();
EXPECT_EQ(begin_iter->tag(), "CLBLL_L.SLICEL_X0.A5FF.ZINI");
EXPECT_EQ(begin_iter->bit(), "31_06");
EXPECT_EQ(++begin_iter, segbits_reader->end());
}
TEST(SegbitsFileReaderTest, FileWithTwoEntries) {
auto segbits_reader = prjxray::SegbitsFileReader::InitWithFile(
"two_entries.segbits");
ASSERT_TRUE(segbits_reader);
auto iter = segbits_reader->begin();
EXPECT_EQ(iter->tag(), "CLBLL_L.SLICEL_X0.A5FF.ZINI");
EXPECT_EQ(iter->bit(), "31_06");
++iter;
EXPECT_EQ(iter->tag(), "CLBLL_L.SLICEL_X0.AFF.ZINI");
EXPECT_EQ(iter->bit(), "31_03");
EXPECT_EQ(++iter, segbits_reader->end());
}

View File

@ -0,0 +1 @@
CLBLL_L.SLICEL_X0.A5FF.ZINI 31_06

View File

@ -0,0 +1 @@
31_06

View File

@ -0,0 +1 @@
CLBLL_L.SLICEL_X0.A5FF.ZINI 31_06

View File

@ -0,0 +1 @@
CLBLL_L.SLICEL_X0.A5FF.ZINI

View File

@ -0,0 +1,2 @@
CLBLL_L.SLICEL_X0.A5FF.ZINI 31_06
CLBLL_L.SLICEL_X0.AFF.ZINI 31_03