OmniSciDB  c0231cc57d
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
foreign_storage::RegexFileBufferParser Class Reference

#include <RegexFileBufferParser.h>

+ Inheritance diagram for foreign_storage::RegexFileBufferParser:
+ Collaboration diagram for foreign_storage::RegexFileBufferParser:

Public Member Functions

 RegexFileBufferParser (const ForeignTable *foreign_table)
 
ParseBufferResult parseBuffer (ParseBufferRequest &request, bool convert_data_blocks, bool columns_are_pre_filtered=false) const override
 
import_export::CopyParams validateAndGetCopyParams (const ForeignTable *foreign_table) const override
 
size_t findRowEndPosition (size_t &alloc_size, std::unique_ptr< char[]> &buffer, size_t &buffer_size, const import_export::CopyParams &copy_params, const size_t buffer_first_row_index, unsigned int &num_rows_in_buffer, FileReader *file_reader) const override
 
void validateFiles (const FileReader *file_reader, const ForeignTable *foreign_table) const override
 

Static Public Member Functions

static void setMaxBufferResize (size_t max_buffer_resize)
 
- Static Public Member Functions inherited from foreign_storage::TextFileBufferParser
static std::map< int,
DataBlockPtr
convertImportBuffersToDataBlocks (const std::vector< std::unique_ptr< import_export::TypedImportBuffer >> &import_buffers)
 
static bool isCoordinateScalar (const std::string_view datum)
 
static void processGeoColumn (std::vector< std::unique_ptr< import_export::TypedImportBuffer >> &import_buffers, size_t &col_idx, const import_export::CopyParams &copy_params, std::list< const ColumnDescriptor * >::iterator &cd_it, std::vector< std::string_view > &row, size_t &import_idx, bool is_null, size_t first_row_index, size_t row_index_plus_one, std::shared_ptr< Catalog_Namespace::Catalog > catalog, const RenderGroupAnalyzerMap *render_group_analyzer_map)
 
static void fillRejectedRowWithInvalidData (const std::list< const ColumnDescriptor * > &columns, std::list< const ColumnDescriptor * >::iterator &cd_it, const size_t col_idx, ParseBufferRequest &request)
 
static bool isNullDatum (const std::string_view datum, const ColumnDescriptor *column, const std::string &null_indicator)
 

Static Public Attributes

static const std::string LINE_REGEX_KEY = "LINE_REGEX"
 
static const std::string LINE_START_REGEX_KEY = "LINE_START_REGEX"
 
static const std::string HEADER_KEY = "HEADER"
 
- Static Public Attributes inherited from foreign_storage::TextFileBufferParser
static const std::string BUFFER_SIZE_KEY = "BUFFER_SIZE"
 

Protected Member Functions

virtual bool regexMatchColumns (const std::string &row_str, const boost::regex &line_regex, size_t logical_column_count, std::vector< std::string > &parsed_columns_str, std::vector< std::string_view > &parsed_columns_sv, const std::string &file_path) const
 
virtual bool shouldRemoveNonMatches () const
 
virtual bool shouldTruncateStringValues () const
 

Static Private Member Functions

static size_t getMaxBufferResize ()
 

Private Attributes

boost::regex line_regex_
 
std::optional< boost::regex > line_start_regex_
 

Static Private Attributes

static size_t max_buffer_resize_
 
static bool skip_first_line_ {false}
 

Detailed Description

Definition at line 23 of file RegexFileBufferParser.h.

Constructor & Destructor Documentation

foreign_storage::RegexFileBufferParser::RegexFileBufferParser ( const ForeignTable foreign_table)

Definition at line 152 of file RegexFileBufferParser.cpp.

153  : line_regex_(get_line_regex(foreign_table))
154  , line_start_regex_(get_line_start_regex(foreign_table)) {}
std::string get_line_regex(const ForeignTable *foreign_table)
std::optional< std::string > get_line_start_regex(const ForeignTable *foreign_table)
std::optional< boost::regex > line_start_regex_

Member Function Documentation

size_t foreign_storage::RegexFileBufferParser::findRowEndPosition ( size_t &  alloc_size,
std::unique_ptr< char[]> &  buffer,
size_t &  buffer_size,
const import_export::CopyParams copy_params,
const size_t  buffer_first_row_index,
unsigned int &  num_rows_in_buffer,
FileReader file_reader 
) const
overridevirtual

Finds and returns the offset of the end of the last row in the given buffer. If the buffer does not contain at least one row, the buffer is extended with more content from the file until a row is read. An exception is thrown if the buffer is extended to a maximum threshold and at least one row has still not been read.

Implements foreign_storage::TextFileBufferParser.

Definition at line 386 of file RegexFileBufferParser.cpp.

References CHECK, CHECK_EQ, CHECK_GT, import_export::delimited_parser::extend_buffer(), foreign_storage::anonymous_namespace{RegexFileBufferParser.cpp}::find_last_end_of_line(), foreign_storage::anonymous_namespace{RegexFileBufferParser.cpp}::get_row_count(), getMaxBufferResize(), foreign_storage::FileReader::isEndOfLastFile(), foreign_storage::FileReader::isScanFinished(), import_export::CopyParams::line_delim, line_regex_, line_start_regex_, foreign_storage::anonymous_namespace{RegexFileBufferParser.cpp}::line_starts_with_regex(), import_export::delimited_parser::max_buffer_resize, and shouldRemoveNonMatches().

393  {
394  CHECK_GT(buffer_size, static_cast<size_t>(0));
395  size_t start_pos{0};
396  size_t end_pos = buffer_size - 1;
397  bool found_end_pos{false};
398  while (!found_end_pos) {
399  try {
400  end_pos = find_last_end_of_line(
401  buffer.get(), buffer_size, start_pos, end_pos, copy_params.line_delim);
402  if (file_reader->isEndOfLastFile()) {
403  CHECK_EQ(end_pos, buffer_size - 1);
404  found_end_pos = true;
405  } else if (line_start_regex_.has_value()) {
406  // When a LINE_START_REGEX option is present and the file reader is not at the end
407  // of file, return the position of the end of line before the last line that
408  // matches the line start regex, since the last line that matches the line start
409  // regex in this buffer may still have to include/concatenate lines beyond this
410  // buffer.
411  CHECK_GT(end_pos, static_cast<size_t>(0));
412  auto old_end_pos = end_pos;
413  end_pos = find_last_end_of_line(buffer.get(),
414  buffer_size,
415  start_pos,
416  old_end_pos - 1,
417  copy_params.line_delim);
418  while (!line_starts_with_regex(
419  buffer.get(), end_pos + 1, old_end_pos, line_start_regex_.value())) {
420  old_end_pos = end_pos;
421  end_pos = find_last_end_of_line(buffer.get(),
422  buffer_size,
423  start_pos,
424  old_end_pos - 1,
425  copy_params.line_delim);
426  }
427  found_end_pos = true;
428  } else {
429  found_end_pos = true;
430  }
431  } catch (InsufficientBufferSizeException& e) {
433  if (alloc_size >= max_buffer_resize || file_reader->isScanFinished()) {
434  throw;
435  }
436  start_pos = buffer_size;
438  buffer, buffer_size, alloc_size, nullptr, file_reader, max_buffer_resize);
439  end_pos = buffer_size - 1;
440  }
441  }
442  CHECK(found_end_pos);
443  num_rows_in_buffer = get_row_count(buffer.get(),
444  0,
445  end_pos,
446  copy_params.line_delim,
448  line_regex_,
450  return end_pos + 1;
451 }
#define CHECK_EQ(x, y)
Definition: Logger.h:230
virtual bool isScanFinished() const =0
virtual bool isEndOfLastFile()=0
#define CHECK_GT(x, y)
Definition: Logger.h:234
void extend_buffer(std::unique_ptr< char[]> &buffer, size_t &buffer_size, size_t &alloc_size, FILE *file, foreign_storage::FileReader *file_reader, size_t max_buffer_resize)
std::optional< boost::regex > line_start_regex_
size_t find_last_end_of_line(const char *buffer, size_t buffer_size, size_t start, size_t end, char line_delim)
#define CHECK(condition)
Definition: Logger.h:222
size_t get_row_count(const char *buffer, size_t start, size_t end, char line_delim, const std::optional< boost::regex > &line_start_regex, const boost::regex &line_regex, bool remove_non_matches)
bool line_starts_with_regex(const char *buffer, size_t start, size_t end, const boost::regex &line_start_regex)

+ Here is the call graph for this function:

size_t foreign_storage::RegexFileBufferParser::getMaxBufferResize ( )
staticprivate

Definition at line 477 of file RegexFileBufferParser.cpp.

References max_buffer_resize_.

Referenced by findRowEndPosition().

477  {
478  return max_buffer_resize_;
479 }

+ Here is the caller graph for this function:

ParseBufferResult foreign_storage::RegexFileBufferParser::parseBuffer ( ParseBufferRequest request,
bool  convert_data_blocks,
bool  columns_are_pre_filtered = false 
) const
overridevirtual

Parses a given file buffer and returns data blocks for each column in the file along with metadata related to rows and row offsets within the buffer.

Implements foreign_storage::TextFileBufferParser.

Definition at line 160 of file RegexFileBufferParser.cpp.

References foreign_storage::ParseBufferRequest::begin_pos, foreign_storage::ParseBufferRequest::buffer, CHECK, foreign_storage::TextFileBufferParser::convertImportBuffersToDataBlocks(), foreign_storage::ParseBufferRequest::copy_params, foreign_storage::ParseBufferRequest::end_pos, foreign_storage::ParseBufferRequest::file_offset, foreign_storage::TextFileBufferParser::fillRejectedRowWithInvalidData(), foreign_storage::ParseBufferRequest::first_row_index, foreign_storage::ParseBufferRequest::foreign_table_schema, foreign_storage::anonymous_namespace{RegexFileBufferParser.cpp}::get_next_row(), foreign_storage::ParseBufferRequest::getCatalog(), foreign_storage::ParseBufferRequest::getColumns(), foreign_storage::ParseBufferRequest::getFilePath(), foreign_storage::ParseBufferRequest::import_buffers, is_null(), foreign_storage::TextFileBufferParser::isNullDatum(), import_export::CopyParams::line_delim, line_regex_, line_start_regex_, StringDictionary::MAX_STRLEN, import_export::CopyParams::null_str, foreign_storage::ParseBufferRequest::process_row_count, foreign_storage::TextFileBufferParser::processGeoColumn(), regexMatchColumns(), foreign_storage::ParseBufferRequest::render_group_analyzer_map, run_benchmark_import::result, shouldRemoveNonMatches(), shouldTruncateStringValues(), and foreign_storage::ParseBufferRequest::track_rejected_rows.

163  {
164  CHECK(request.buffer);
165  char* buffer_start = request.buffer.get() + request.begin_pos;
166  const char* buffer_end = request.buffer.get() + request.end_pos;
167 
168  std::vector<size_t> row_offsets;
169  row_offsets.emplace_back(request.file_offset + request.begin_pos);
170 
171  size_t current_row_id = 0;
172  size_t row_count = 0;
173  auto logical_column_count = request.foreign_table_schema->getLogicalColumns().size();
174  std::vector<std::string> parsed_columns_str;
175  parsed_columns_str.reserve(logical_column_count);
176  std::vector<std::string_view> parsed_columns_sv;
177  parsed_columns_sv.reserve(logical_column_count);
178 
179  ParseBufferResult result{};
180 
181  std::string row_str;
182  size_t remaining_row_count = request.process_row_count;
183  auto curr = buffer_start;
184  while (curr < buffer_end && remaining_row_count > 0) {
185  try {
186  row_str = get_next_row(
187  curr, buffer_end - 1, request.copy_params.line_delim, line_start_regex_);
188  curr += row_str.length() + 1;
189  current_row_id = row_count++;
190  remaining_row_count--;
191 
192  bool skip_all_columns =
193  std::all_of(request.import_buffers.begin(),
194  request.import_buffers.end(),
195  [](const auto& import_buffer) { return !import_buffer; });
196  if (!skip_all_columns) {
197  auto columns = request.getColumns();
198 
199  bool set_all_nulls = false;
200  try {
201  parsed_columns_str.clear();
202  parsed_columns_sv.clear();
203  set_all_nulls = regexMatchColumns(row_str,
204  line_regex_,
205  logical_column_count,
206  parsed_columns_str,
207  parsed_columns_sv,
208  request.getFilePath());
209  if (set_all_nulls && shouldRemoveNonMatches()) {
210  current_row_id = row_count--;
211  remaining_row_count++;
212  continue;
213  }
214  } catch (const ForeignStorageException& e) {
215  if (request.track_rejected_rows) {
216  result.rejected_rows.insert(current_row_id);
217  auto cd_it = columns.begin();
218  fillRejectedRowWithInvalidData(columns, cd_it, 0, request);
219  continue;
220  } else {
221  throw;
222  }
223  }
224 
225  size_t parsed_column_index = 0;
226  size_t import_buffer_index = 0;
227 
228  for (auto cd_it = columns.begin(); cd_it != columns.end(); ++cd_it) {
229  auto cd = *cd_it;
230  const auto& column_type = cd->columnType;
231  if (request.import_buffers[import_buffer_index]) {
232  bool is_null = false;
233  try {
234  is_null =
235  (set_all_nulls || isNullDatum(parsed_columns_sv[parsed_column_index],
236  cd,
237  request.copy_params.null_str));
238  } catch (const std::exception& e) {
239  if (request.track_rejected_rows) {
240  result.rejected_rows.insert(current_row_id);
242  columns, cd_it, import_buffer_index, request);
243  break; // skip rest of row
244  } else {
245  throw;
246  }
247  }
248  if (column_type.is_geometry()) {
249  auto starting_import_buffer_index = import_buffer_index;
250  try {
251  processGeoColumn(request.import_buffers,
252  import_buffer_index,
253  request.copy_params,
254  cd_it,
255  parsed_columns_sv,
256  parsed_column_index,
257  is_null,
258  request.first_row_index,
259  row_count,
260  request.getCatalog(),
261  request.render_group_analyzer_map);
262  } catch (const std::exception& e) {
263  if (request.track_rejected_rows) {
264  result.rejected_rows.insert(current_row_id);
266  columns, cd_it, starting_import_buffer_index, request);
267  break; // skip rest of row
268  } else {
269  throw;
270  }
271  }
272  // Skip remaining physical columns
273  for (int i = 0; i < cd->columnType.get_physical_cols(); ++i) {
274  ++cd_it;
275  }
276  } else {
277  try {
278  auto& column_sv = parsed_columns_sv[parsed_column_index];
279  if (column_type.is_string() && shouldTruncateStringValues() &&
280  column_sv.length() > StringDictionary::MAX_STRLEN) {
281  column_sv = column_sv.substr(0, StringDictionary::MAX_STRLEN);
282  }
283  request.import_buffers[import_buffer_index]->add_value(
284  cd,
285  parsed_columns_sv[parsed_column_index],
286  is_null,
287  request.copy_params);
288  } catch (const std::exception& e) {
289  if (request.track_rejected_rows) {
290  result.rejected_rows.insert(current_row_id);
292  columns, cd_it, import_buffer_index, request);
293  break; // skip rest of row
294  } else {
295  throw;
296  }
297  }
298  parsed_column_index++;
299  import_buffer_index++;
300  }
301  } else {
302  // Skip column
303  for (int i = 0; i < column_type.get_physical_cols(); i++) {
304  import_buffer_index++;
305  cd_it++;
306  }
307  parsed_column_index++;
308  import_buffer_index++;
309  }
310  }
311  }
312  } catch (const ForeignStorageException& e) {
313  throw;
314  } catch (const std::exception& e) {
315  throw ForeignStorageException("Parsing failure \"" + std::string(e.what()) +
316  "\" in row \"" + row_str + "\" in file \"" +
317  request.getFilePath() + "\"");
318  }
319  }
320  row_offsets.emplace_back(request.file_offset + (curr - request.buffer.get()));
321 
322  result.row_offsets = row_offsets;
323  result.row_count = row_count;
324  if (convert_data_blocks) {
325  result.column_id_to_data_blocks_map =
326  convertImportBuffersToDataBlocks(request.import_buffers);
327  }
328  return result;
329 }
static std::map< int, DataBlockPtr > convertImportBuffersToDataBlocks(const std::vector< std::unique_ptr< import_export::TypedImportBuffer >> &import_buffers)
static void fillRejectedRowWithInvalidData(const std::list< const ColumnDescriptor * > &columns, std::list< const ColumnDescriptor * >::iterator &cd_it, const size_t col_idx, ParseBufferRequest &request)
CONSTEXPR DEVICE bool is_null(const T &value)
std::string get_next_row(const char *curr, const char *buffer_end, char line_delim, const std::optional< boost::regex > &line_start_regex)
std::optional< boost::regex > line_start_regex_
virtual bool regexMatchColumns(const std::string &row_str, const boost::regex &line_regex, size_t logical_column_count, std::vector< std::string > &parsed_columns_str, std::vector< std::string_view > &parsed_columns_sv, const std::string &file_path) const
#define CHECK(condition)
Definition: Logger.h:222
static void processGeoColumn(std::vector< std::unique_ptr< import_export::TypedImportBuffer >> &import_buffers, size_t &col_idx, const import_export::CopyParams &copy_params, std::list< const ColumnDescriptor * >::iterator &cd_it, std::vector< std::string_view > &row, size_t &import_idx, bool is_null, size_t first_row_index, size_t row_index_plus_one, std::shared_ptr< Catalog_Namespace::Catalog > catalog, const RenderGroupAnalyzerMap *render_group_analyzer_map)
static bool isNullDatum(const std::string_view datum, const ColumnDescriptor *column, const std::string &null_indicator)
static constexpr size_t MAX_STRLEN

+ Here is the call graph for this function:

bool foreign_storage::RegexFileBufferParser::regexMatchColumns ( const std::string &  row_str,
const boost::regex &  line_regex,
size_t  logical_column_count,
std::vector< std::string > &  parsed_columns_str,
std::vector< std::string_view > &  parsed_columns_sv,
const std::string &  file_path 
) const
protectedvirtual

Reimplemented in foreign_storage::LogFileBufferParser.

Definition at line 331 of file RegexFileBufferParser.cpp.

References CHECK_GT, and foreign_storage::throw_number_of_columns_mismatch_error().

Referenced by parseBuffer(), and foreign_storage::LogFileBufferParser::regexMatchColumns().

337  {
338  boost::smatch match;
339  bool set_all_nulls{false};
340  if (boost::regex_match(row_str, match, line_regex)) {
341  auto matched_column_count = match.size() - 1 + parsed_columns_sv.size();
342  if (logical_column_count != matched_column_count) {
344  logical_column_count, matched_column_count, file_path);
345  }
346  CHECK_GT(match.size(), static_cast<size_t>(1));
347  for (size_t i = 1; i < match.size(); i++) {
348  parsed_columns_str.emplace_back(match[i].str());
349  parsed_columns_sv.emplace_back(parsed_columns_str.back());
350  }
351  } else {
352  parsed_columns_str.clear();
353  parsed_columns_sv =
354  std::vector<std::string_view>(logical_column_count, std::string_view{});
355  set_all_nulls = true;
356  }
357  return set_all_nulls;
358 }
#define CHECK_GT(x, y)
Definition: Logger.h:234
void throw_number_of_columns_mismatch_error(size_t num_table_cols, size_t num_file_cols, const std::string &file_path)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void foreign_storage::RegexFileBufferParser::setMaxBufferResize ( size_t  max_buffer_resize)
static
bool foreign_storage::RegexFileBufferParser::shouldRemoveNonMatches ( ) const
protectedvirtual

Reimplemented in foreign_storage::LogFileBufferParser.

Definition at line 481 of file RegexFileBufferParser.cpp.

Referenced by findRowEndPosition(), and parseBuffer().

481  {
482  return false;
483 }

+ Here is the caller graph for this function:

bool foreign_storage::RegexFileBufferParser::shouldTruncateStringValues ( ) const
protectedvirtual

Reimplemented in foreign_storage::LogFileBufferParser.

Definition at line 485 of file RegexFileBufferParser.cpp.

Referenced by parseBuffer().

485  {
486  return false;
487 }

+ Here is the caller graph for this function:

import_export::CopyParams foreign_storage::RegexFileBufferParser::validateAndGetCopyParams ( const ForeignTable foreign_table) const
overridevirtual

Validates foreign table parse options and returns a CopyParams object upon successful validation. An exception is thrown if validation fails.

Implements foreign_storage::TextFileBufferParser.

Definition at line 360 of file RegexFileBufferParser.cpp.

References foreign_storage::TextFileBufferParser::BUFFER_SIZE_KEY, HEADER_KEY, import_export::kHasHeader, import_export::kNoHeader, foreign_storage::OptionsContainer::options, import_export::CopyParams::plain_text, foreign_storage::AbstractFileStorageDataWrapper::THREADS_KEY, and foreign_storage::anonymous_namespace{CsvFileBufferParser.cpp}::validate_and_get_bool_value().

361  {
362  import_export::CopyParams copy_params{};
363  copy_params.plain_text = true;
364  auto has_header = validate_and_get_bool_value(foreign_table, HEADER_KEY);
365  if (has_header.has_value()) {
366  if (has_header.value()) {
367  copy_params.has_header = import_export::ImportHeaderRow::kHasHeader;
368  } else {
369  copy_params.has_header = import_export::ImportHeaderRow::kNoHeader;
370  }
371  } else {
372  // By default, regex parsed files are not assumed to have headers.
373  copy_params.has_header = import_export::ImportHeaderRow::kNoHeader;
374  }
375  if (auto it = foreign_table->options.find(BUFFER_SIZE_KEY);
376  it != foreign_table->options.end()) {
377  copy_params.buffer_size = std::stoi(it->second);
378  }
379  if (auto it = foreign_table->options.find(AbstractFileStorageDataWrapper::THREADS_KEY);
380  it != foreign_table->options.end()) {
381  copy_params.threads = std::stoi(it->second);
382  }
383  return copy_params;
384 }
std::optional< bool > validate_and_get_bool_value(const ForeignTable *foreign_table, const std::string &option_name)

+ Here is the call graph for this function:

void foreign_storage::RegexFileBufferParser::validateFiles ( const FileReader file_reader,
const ForeignTable foreign_table 
) const
overridevirtual

Performs basic validation of files to be parsed.

Implements foreign_storage::TextFileBufferParser.

Definition at line 453 of file RegexFileBufferParser.cpp.

References CHECK, foreign_storage::anonymous_namespace{RegexFileBufferParser.cpp}::get_line_start_regex(), foreign_storage::FileReader::getFirstLineForEachFile(), parse_ast::line, line_start_regex_, and foreign_storage::anonymous_namespace{RegexFileBufferParser.cpp}::line_starts_with_regex().

454  {
455  if (line_start_regex_.has_value()) {
456  // When a LINE_START_REGEX option is specified, at least the first line in each file
457  // has to start with the specified regex.
458  auto first_line_by_file_path = file_reader->getFirstLineForEachFile();
459  for (const auto& [file_path, line] : first_line_by_file_path) {
460  if (!line.empty() &&
462  line.c_str(), 0, line.length() - 1, line_start_regex_.value())) {
463  auto line_start_regex = get_line_start_regex(foreign_table);
464  CHECK(line_start_regex.has_value());
465  throw ForeignStorageException{"First line in file \"" + file_path +
466  "\" does not match line start regex \"" +
467  line_start_regex.value() + "\""};
468  }
469  }
470  }
471 }
std::optional< std::string > get_line_start_regex(const ForeignTable *foreign_table)
std::optional< boost::regex > line_start_regex_
tuple line
Definition: parse_ast.py:10
#define CHECK(condition)
Definition: Logger.h:222
bool line_starts_with_regex(const char *buffer, size_t start, size_t end, const boost::regex &line_start_regex)

+ Here is the call graph for this function:

Member Data Documentation

const std::string foreign_storage::RegexFileBufferParser::HEADER_KEY = "HEADER"
inlinestatic

Definition at line 50 of file RegexFileBufferParser.h.

Referenced by validateAndGetCopyParams().

boost::regex foreign_storage::RegexFileBufferParser::line_regex_
private

Definition at line 73 of file RegexFileBufferParser.h.

Referenced by findRowEndPosition(), and parseBuffer().

std::optional<boost::regex> foreign_storage::RegexFileBufferParser::line_start_regex_
private

Definition at line 74 of file RegexFileBufferParser.h.

Referenced by findRowEndPosition(), parseBuffer(), and validateFiles().

const std::string foreign_storage::RegexFileBufferParser::LINE_START_REGEX_KEY = "LINE_START_REGEX"
inlinestatic
size_t foreign_storage::RegexFileBufferParser::max_buffer_resize_
inlinestaticprivate
bool foreign_storage::RegexFileBufferParser::skip_first_line_ {false}
inlinestaticprivate

Definition at line 71 of file RegexFileBufferParser.h.


The documentation for this class was generated from the following files: