mirror of https://github.com/openXC7/prjxray.git
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:
parent
36f429127f
commit
3e203b956b
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
CLBLL_L.SLICEL_X0.A5FF.ZINI 31_06
|
||||
|
|
@ -0,0 +1 @@
|
|||
31_06
|
||||
|
|
@ -0,0 +1 @@
|
|||
CLBLL_L.SLICEL_X0.A5FF.ZINI 31_06
|
||||
|
|
@ -0,0 +1 @@
|
|||
CLBLL_L.SLICEL_X0.A5FF.ZINI
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
CLBLL_L.SLICEL_X0.A5FF.ZINI 31_06
|
||||
CLBLL_L.SLICEL_X0.AFF.ZINI 31_03
|
||||
Loading…
Reference in New Issue