#include <cstddef>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <vector>
int at(const std::vector<int>& data,std::size_t rows,std::size_t cols,std::size_t rs,std::size_t cs,std::size_t r,std::size_t c) {
    if(r>=rows || c>=cols) throw std::out_of_range("coordinate");
    const auto maximum=std::numeric_limits<std::size_t>::max();
    if((r!=0 && rs>maximum/r)||(c!=0 && cs>maximum/c)) throw std::out_of_range("stride overflow");
    const auto a=r*rs,b=c*cs;
    if(b>maximum-a || a+b>=data.size()) throw std::out_of_range("storage");
    return data[a+b];
}
int main() {
    const std::vector<int> data{1,2,3,4,5,6};
    if(at(data,2,3,3,1,1,2)!=6) throw std::runtime_error("row major");
    int rejected=0;
    try {
        const int unexpected=at(data,3,2,1,3,0,2);
        std::cout<<"unexpected invalid-coordinate value="<<unexpected<<'\n';
        return 1;
    } catch(const std::out_of_range&){++rejected;}
    try {
        const int unexpected=at(data,3,2,std::numeric_limits<std::size_t>::max(),3,2,1);
        std::cout<<"unexpected invalid-stride value="<<unexpected<<'\n';
        return 1;
    } catch(const std::out_of_range&){++rejected;}
    if(rejected!=2) throw std::runtime_error("bounds");
    std::cout<<"transpose=";
    for(std::size_t r=0;r<3;++r){if(r)std::cout<<';';for(std::size_t c=0;c<2;++c)std::cout<<(c?",":"")<<at(data,3,2,1,3,r,c);}
    std::cout<<'\n';
}
