#pragma once #include #include template class NonUniformLookupTable; template class NonUniformLookupTableParams { public: friend NonUniformLookupTable; int size() const { return (int) entries.size(); } private: class Entry { public: T x; T y; T a; }; using container = std::map; bool isFinalized = false; container entries; }; template class NonUniformLookupTable { public: NonUniformLookupTable() = delete; static void addPoint(NonUniformLookupTableParams& params, T x, T y); static void finalize(NonUniformLookupTableParams& params); static T lookup(NonUniformLookupTableParams& params, T x); }; template inline void NonUniformLookupTable::addPoint(NonUniformLookupTableParams& params, T x, T y) { using Entry = typename NonUniformLookupTableParams::Entry; Entry e; e.x = x; e.y = y; params.entries.insert(std::pair(x, e)); } template inline void NonUniformLookupTable::finalize(NonUniformLookupTableParams& params) { assert(!params.isFinalized); using iterator = typename std::map::Entry>::iterator; iterator it; //typename std::map::Entry>::iterator it; for (it = params.entries.begin(); it != params.entries.end(); ++it) { iterator it_next = it; ++it_next; // Will now generate a line segment from this entry to the next if (it_next == params.entries.end()) { it->second.a = 0; } else { T a = (it_next->second.y - it->second.y) / (it_next->second.x - it->second.x); it->second.a = a; } } params.isFinalized = true; } template inline T NonUniformLookupTable::lookup(NonUniformLookupTableParams& params, T x) { assert(params.isFinalized); assert(!params.entries.empty()); auto lb_init = params.entries.lower_bound(x); auto lb = lb_init; if (lb == params.entries.end()) { return params.entries.rbegin()->second.y; } if (x >= lb->second.x) { // this could only happen if we hit equal } else { // added this case to keep mac from crashing, as we were trying to decrement begin() if (lb == params.entries.begin()) { return lb_init->second.y; } --lb; if (lb == params.entries.end()) { // I thing now that above is fixed this won't happen? assert(false); return lb_init->second.y; } } // Now that we have the right entry, interpolate. T ret = lb->second.a * (x - lb->second.x) + lb->second.y; return ret; }