// Stage 05: a class owns its vector and protects a small, explicit value range.
#include <iostream>
#include <span>
#include <stdexcept>
#include <vector>
class ReadingBatch {
    std::vector<int> readings_;
public:
    explicit ReadingBatch(const std::vector<int>& readings):readings_(readings) {
        if(readings_.size()>1024) throw std::invalid_argument("batch too large");
        for(const int value:readings_)
            if(value < -1000000 || value > 1000000)
                throw std::invalid_argument("reading range");
    }
    std::span<const int> view() const {return readings_;}
    long long total() const {
        long long result=0;
        for(const int value:readings_) result+=value;
        return result;
    }
    // Rule of Zero: vector releases its storage when this batch is destroyed.
    // No handwritten delete, copy operation, or destructor is necessary.
};
int main() {
    const ReadingBatch batch{{3,1,4,1,5}};
    long long saved=0;
    {const ReadingBatch temporary{{1,2}};saved=temporary.total();}
    // saved owns a number. It does not borrow the destroyed temporary's storage.
    int rejected=0;
    try {const ReadingBatch bad{{1000001}};} catch(const std::invalid_argument&) {++rejected;}
    try {const ReadingBatch bad{std::vector<int>(1025,0)};} catch(const std::invalid_argument&) {++rejected;}
    const ReadingBatch empty{std::vector<int>{}},boundary{{-1000000,1000000}};
    const ReadingBatch largest{std::vector<int>(1024,1000000)};
    if(batch.total()!=14 || batch.view().size()!=5 || saved!=3 || rejected!=2 ||
       empty.view().size()!=0 || empty.total()!=0 || boundary.total()!=0 ||
       largest.total()!=1024000000LL) return 1;
    std::cout<<"batch=14 saved_after_scope="<<saved<<" rejected="<<rejected<<'\n';
}
