#include "prism_engineering/allocator_lab.hpp" #include #include #include #include #include #include #include #include using namespace prism_engineering; namespace { int checks{}; void check(bool value,std::string_view why) { if(!value) throw std::runtime_error{std::string{why}}; ++checks; } void allocator_transfers() { using Vector=std::pmr::vector; using Traits=std::allocator_traits; static_assert(!Traits::propagate_on_container_copy_assignment::value); static_assert(!Traits::propagate_on_container_move_assignment::value); static_assert(!Traits::propagate_on_container_swap::value); CountingResource a{*std::pmr::new_delete_resource()}, b{*std::pmr::new_delete_resource()}; check(a==a && !(a==b),"identity-based resource equality"); { Vector source{{4,5,6},&a}; Vector copied{source}; check(copied.get_allocator().resource()==std::pmr::get_default_resource(),"ordinary PMR copy selects current default resource"); check(copied==source && copied.data()!=source.data(),"copy owns independent elements"); Vector explicit_copy{source,&b}; check(explicit_copy.get_allocator().resource()==&b,"explicit copy uses selected resource"); auto* original_data=source.data(); Vector moved{std::move(source)}; check(moved.get_allocator().resource()==&a && moved.data()==original_data,"ordinary move preserves allocator and transfers buffer"); const auto before_move_allocations=b.counts().calls; Vector unequal_move{std::move(moved),&b}; check(unequal_move.get_allocator().resource()==&b && unequal_move==Vector({4,5,6}),"allocator-extended unequal move uses destination resource"); check(b.counts().calls>before_move_allocations,"unequal allocator move allocates destination storage"); Vector assigned{&a}; assigned=unequal_move; check(assigned.get_allocator().resource()==&a && assigned==unequal_move,"copy assignment keeps destination resource"); assigned=std::move(unequal_move); check(assigned.get_allocator().resource()==&a && assigned==Vector({4,5,6}),"unequal move assignment keeps destination resource"); Vector same_a{{1,2},&a}, same_b{{3,4},&a}; same_a.swap(same_b); // Equal allocators; never demonstrate unequal PMR swap. check(same_a==Vector({3,4}),"swap with equal allocators"); } check(a.counts().live_bytes==0 && b.counts().live_bytes==0,"borrowers destroy before resources"); } void rendering_and_exhaustion() { const auto baseline=render_plain(); check(baseline.pixels.size()==4096,"64x64 output"); check(baseline.pixels.front()==Rgb{240,64,32},"known triangle interior"); check(baseline.pixels.back()==Rgb{24,48,160},"known background"); // At pixel (32,31), subpixel sums are126,127,127,128: three red, one blue. check(baseline.pixels[31U*64U+32U]==Rgb{186,60,64},"independent edge coverage average"); for(const auto choice:{ResourceChoice::ordinary,ResourceChoice::monotonic,ResourceChoice::pool}) { const auto result=measure_render(choice); check(result.image.pixels==baseline.pixels,"resource policy preserves exact pixels"); check(result.requests.calls>0 && result.requests.live_bytes==0,"logical scratch requests are balanced"); check(result.upstream_before_release.calls>0,"upstream sees real requests rather than copied instrumentation"); check(result.upstream_after_release.live_bytes==0,"resource release returns upstream storage"); check(result.elapsed_nanoseconds>=0,"elapsed duration, not CPU time"); if(choice==ResourceChoice::monotonic)check(result.upstream_before_release.live_bytes>0,"arena retains after borrower destruction"); } alignas(std::max_align_t) std::array backing{}; std::pmr::monotonic_buffer_resource bounded{backing.data(),backing.size(),std::pmr::null_memory_resource()}; CountingResource requests{bounded}; PreparedImage promoted=baseline; const auto expected_checksum=image_checksum(promoted); bool failed{}; { std::pmr::vector values{&requests}; values.push_back(42); try { values.reserve(4096); } catch(const std::bad_alloc&) { failed=true; } check(failed && values.size()==1 && values.front()==42,"failed reserve preserves existing values"); } check(requests.counts().live_bytes==0,"all borrowers end before reset"); bounded.release(); check(image_checksum(promoted)==expected_checksum,"ordinary promoted image survives release"); bool render_failed{}; try { (void)render_tiles(bounded); } catch(const std::bad_alloc&) { render_failed=true; } check(render_failed,"bounded render scratch failure is observable"); } } int main() { try { allocator_transfers(); rendering_and_exhaustion(); std::cout<