// ================================================================= //
//                                                                   //
//   File      : mod_rlimit.h                                        //
//   Purpose   : locally modify resources (e.g. available memory)    //
//                                                                   //
//   Coded by Ralf Westram (coder@reallysoft.de) in September 2017   //
//   http://www.arb-home.de/                                         //
//                                                                   //
// ================================================================= //

#ifndef MOD_RLIMIT_H
#define MOD_RLIMIT_H

#ifndef ARB_ASSERT_H
#include <arb_assert.h>
#endif
#ifndef _SYS_RESOURCE_H
#include <sys/resource.h>
#endif

class ModRLimit {
    int    resource;
    rlimit previous;
    rlimit modified;

    int last_errno;

    bool succeeded(int res) {
        if (res == 0) return true;
        if (last_errno) { // dump before overwrite
            dump_error(stderr);
        }
        last_errno = errno;
        return false;
    }
    void dump_limitation(const rlimit& from, const rlimit& to) const {
        fprintf(stderr, "limited resource %i to %li (was: %li of %li)\n",
                resource,
                to.rlim_cur,
                from.rlim_cur,
                from.rlim_max);
    }

public:

    ModRLimit(int resource_, rlim_t newLimit) : // for resource see (manual-entry "getrlimit")
        resource(resource_),
        last_errno(0)
    {
        if (succeeded(getrlimit(resource, &previous))) {
            modified          = previous;
            modified.rlim_cur = newLimit;
            if (succeeded(setrlimit(resource, &modified))) {
                dump_limitation(previous, modified);
            }
        }
        if (last_errno) dump_error(stderr);
    }
    ~ModRLimit() {
        if (succeeded(setrlimit(resource, &previous))) {
            dump_limitation(modified, previous);
        }
        else {
            dump_error(stderr);
        }
    }

    int get_errno() const { return last_errno; }
    void dump_error(FILE *out) {
        arb_assert(last_errno);
        fputs("Error in ModRLimit: ", out);
        fputs(strerror(last_errno), out);
        fputc('\n', out);
        last_errno = 0;
    }
};

#else
#error mod_rlimit.h included twice
#endif // MOD_RLIMIT_H
