Inside the companion
Renderer Engineering
Explore bounded image work, allocator lifetimes, cancellation, and Asio coroutines.
Project files 15
Test the resource lifetime
Known pixels, resource accounting, PMR copy and move behavior, and exhaustion.
#include "prism_engineering/allocator_lab.hpp"
#include <array>
#include <iostream>
#include <limits>
#include <new>
#include <stdexcept>
#include <string_view>
#include <type_traits>
#include <utility>
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<int>;
using Traits=std::allocator_traits<Vector::allocator_type>;
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<std::byte,64> 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<int> 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<<checks<<" allocator checks passed\n"; return 0; }
catch(const std::exception& error) { std::cerr<<error.what()<<'\n'; return 1; }
}
This is the file included with the course. Copy and download give you its complete source.
Taking your work offline? Download all course companions
