Skip to content

Chain

The chain class provides multi-file processing with sequential iteration and parallel processing support.

hipo::chain

Construction

explicit chain(int threads = 0, bool progress = true, bool verbose = false);
  • threads: Number of worker threads (0 = auto-detect hardware concurrency)
  • progress: Show progress bar during processing
  • verbose: Enable verbose output

File Management

int add(std::string_view filename);           // add a single file
int add(std::vector<std::string>& filenames); // add multiple files
int add_pattern(std::string_view pattern);    // add files matching glob pattern
void clear();                                  // remove all files
// Glob patterns
ch.add_pattern("data/*.hipo");
ch.add_pattern("run_???.hipo");

File Information

std::size_t size() const;                     // number of files
bool empty() const;
const FileInfo& operator[](std::size_t idx);  // file info by index
std::vector<FileInfo>& files();               // all file infos

Configuration

void set_tags(const std::vector<long>& tags);
void set_threads(int n);
void set_progress(bool show);
void set_verbose(bool verbose);

Validation

void open(bool validate_all = true);

Validates files and optionally loads metadata (event counts, record counts).

Sequential Iteration

iterator begin();
iterator end();

Enables range-based for loops:

hipo::chain ch;
ch.add("file1.hipo");
ch.add("file2.hipo");

for (auto& [event, file_idx, event_idx] : ch) {
    auto particles = event.getBank("REC::Particle");
    // process...
}

Parallel Processing

template<typename ProcessFunc>
void process(ProcessFunc&& func, double percentage = 100.0);

Uses record-level parallelism: each thread grabs entire records and processes all events within them sequentially.

ch.process([](auto& event, int file_idx, long event_idx) {
    auto particles = event.getBank("REC::Particle");
    // thread-safe processing...
});

Filtered Processing

template<typename ProcessFunc>
void process_filtered(ProcessFunc&& func,
                      const std::vector<std::string>& required_banks,
                      double percentage = 100.0);

Only processes events containing all specified banks:

ch.process_filtered([](auto& event, int file_idx, long event_idx) {
    auto parts = event.getBank("REC::Particle");
    auto calos = event.getBank("REC::Calorimeter");
    // both banks guaranteed to have data
}, {"REC::Particle", "REC::Calorimeter"});

File-Level Operations

template<typename FileFunc>
void for_each_file(FileFunc&& func);
ch.for_each_file([](hipo::reader& r, const hipo::FileInfo& info) {
    printf("File %d: %s (%ld events)\n",
           info.index, info.filename.c_str(), info.total_events);
});

Scanning & Display

void scan();              // scan and display file info with progress
void list() const;        // print file list
void show_all_info();     // detailed info for all files
void print_statistics();  // processing statistics

Statistics

const ChainStatistics& statistics() const;
long total_events();

Configuration Access

bool any_has_config(std::string_view name);
std::optional<std::string> get_config(std::string_view name);

hipo::FileInfo

struct FileInfo {
    std::string filename;
    int index{0};
    long total_events{-1};       // -1 = not yet loaded
    int num_records{-1};
    std::uintmax_t file_size{0};
    bool is_valid{true};
    std::string error_message;

    bool metadata_loaded() const;
    std::string size_string() const;  // human-readable size
};

hipo::ChainStatistics

struct ChainStatistics {
    std::atomic<long> total_events{0};
    std::atomic<long> events_processed{0};
    std::atomic<long> events_skipped{0};

    double elapsed_seconds() const;
    double throughput() const;        // events/sec
};

hipo::chain_event

Event wrapper providing bank access via dictionary:

bank getBank(const std::string& name);
bank get_bank(const std::string& name);  // snake_case alias
event* raw();
explicit operator bool() const;