{
    mode: "facet",
    output_cpp_dir: "src/alloc2/facet",
    output_hpp_dir: "include/xo/alloc2",
    output_impl_subdir: "gc",
    includes: [
        "<xo/alloc2/Allocator_basic.hpp>",
        "<xo/alloc2/Generation.hpp>",
        "<xo/alloc2/role.hpp>",
//        "<cstdint>",
//        "<cstddef>",
    ],
    // extra includes in GCObject.hpp, if any
    user_hpp_includes: [
        //        "\"gc/RCollector_aux.hpp\"",   // not usable here,
    ],
    namespace1: "xo",
    namespace2: "mm",
    pretext: [
        "namespace xo { namespace mm { class AGCObject; } }",
        "namespace xo { namespace mm { class IGCObject_Any; } }",
        "// more pretext here..",
    ],
    facet: "Collector",
    detail_subdir: "gc",
    brief: "garbage collector interface",
    using_doxygen: true,
    doc: [
        "A collector must also suppose the @ref AAllocator facet, see also"
    ],
    types: [
        // using size_type = std::size_t;
        {
            name: "size_type",
            doc: ["allocation size type"],
            definition: "std::size_t",
        },
    ],
    const_methods: [
        // size_type allocated(Generation g, Role r) const noexcept
        {
            name: "allocated",
            doc: ["memory in use for this collector"],
            return_type: "size_type",
            args: [
                {type: "Generation", name: "g"},
                {type: "Role", name: "r"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // size_type committed(Generation g, Role r) const noexcept
        {
            name: "committed",
            doc: ["memory committed for this collector"],
            return_type: "size_type",
            args: [
                {type: "Generation", name: "g"},
                {type: "Role", name: "r"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // size_type reserved(Generation g, Role r) const noexcept
        {
            name: "reserved",
            doc: ["address space reserved for this collector"],
            return_type: "size_type",
            args: [
                {type: "Generation", name: "g"},
                {type: "Role", name: "r"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // int32_t locate() const noexcept
        {
            name: "locate_address",
            doc: [
                "Location of object in collector. -1 if not in collector memory.",
                "Other negative values represent collector error states (good luck!).",
                "Exact meaning of non-negative values up to collector implementation"
            ],
            return_type: "std::int32_t",
            args: [
                {type: "const void *", name: "addr"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // bool contains(Role r, const void * addr) const noexcept
        {
            name: "contains",
            doc: ["true if gc responsible for data at @p addr, and data belongs to Role @p r"],
            return_type: "bool",
            args: [
                {type: "Role", name: "r"},
                {type: "const void *", name: "addr"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // bool is_type_installed(typeseq tseq) const noexcept;
        {
            name: "is_type_installed",
            doc: ["true iff gc-aware object of type @p tseq is installed in this collector"],
            return_type: "bool",
            args: [
                {type: "typeseq", name: "tseq"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // bool report_statistics(obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output);
        {
            name: "report_statistics",
            doc: [
                "Report gc statistics, at discretion of collector implementation.",
                "Creates dictionary using memory from @p report_mm.",
                "If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.",
                "Avoiding obj<AGCObject> return type to avoid #include cycle"
            ],
            return_type: "bool",
            args: [
                {type: "obj<AAllocator>", name: "report_mm"},
                {type: "obj<AAllocator>", name: "error_mm"},
                {type: "obj<AGCObject> *", name: "output"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // bool report_types(obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output);
        {
            name: "report_object_types",
            doc: [
                "Report gc object types, at discretion of collector implementation.",
                "Creates dictionary using memory from @p report_mm.",
                "If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.",
                "Avoiding obj<AGCObject> return type to avoid #include cycle"
            ],
            return_type: "bool",
            args: [
                {type: "obj<AAllocator>", name: "report_mm"},
                {type: "obj<AAllocator>", name: "error_mm"},
                {type: "obj<AGCObject> *", name: "output"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
        // bool report_object_ages(obj<AAllocator> report_mm, obj<AAllocator> error_mm, obj<AGCObject> * output);
        {
            name: "report_object_ages",
            doc: [
                "Report gc object ages, at discretion of collector implementation.",
                "Creates array of dictionaries using memory from @p report_mm.",
                "Each dictionary has keys n-live and bytes, indexed by object age.",
                "If unable to comply (e.g. oom), return runtime error allocated from @p error_mm.",
                "Avoiding obj<AGCObject> return type to avoid #include cycle",
            ],
            return_type: "bool",
            args: [
                {type: "obj<AAllocator>", name: "report_mm"},
                {type: "obj<AAllocator>", name: "error_mm"},
                {type: "obj<AGCObject> *", name: "output"},
            ],
            const: true,
            noexcept: true,
            attributes: [],
        },
    ],
    nonconst_methods: [
        // bool install_type(const AGCObject & iface)
        {
            name: "install_type",
            doc: [
                "install interface @p iface for representation with typeseq @p tseq",
                "in collector @p d.",
                "",
                "The type AGCObject_Any here is misleading.",
                "Will have been replaced by an instance of",
                "  @c AGCObject_Xfer<DFoo,AGCObject_DFoo> for some @c DFoo",
                "in which case calls through @c std::launder(&iface)",
                "will properly act on @c DFoo.",
                "",
                "Return false if installation fails (e.g. memory exhausted)"
            ],
            return_type: "bool",
            args: [
                {type: "const AGCObject &", name: "iface"},
            ],
            const: false,
            noexcept: false,
            attributes: [],
        },
        // void add_gc_root_poly(obj<AGCObject> * p_root)
        {
            name: "add_gc_root_poly",
            doc: [
                "add gc root with address @p p_root. gc will preserve subgraph at this address"
            ],
            return_type: "void",
            args: [
                {type: "obj<AGCObject> *", name: "p_root"},
            ],
            const: false,
            noexcept: false,
            attributes: [],
        },
        // void remove_gc_root_poly(obj<AGCObject> * p_root)
        {
            name: "remove_gc_root_poly",
            doc: [
                "remove gc root with address @p p_root. Reverse effect of prior add_gc_root_poly call"
            ],
            return_type: "void",
            args: [
                {type: "obj<AGCObject> *", name: "p_root"},
            ],
            const: false,
            noexcept: false,
            attributes: [],
        },
        // void request_gc(Generation upto)
        {
            name: "request_gc",
            doc: [
                "Request immediate collection.",
                "  1. if collection is enabled, immediately collect all generations",
                "     up to (but not including) g",
                "  2. may nevertheless escalate to older generations,",
                "     depending on collector state.",
                "  3. if collection is currently disabled,",
                "     collection will trigger the next time gc is enabled.",
                "",
            ],
            return_type: "void",
            args: [
                {type: "Generation", name: "upto"},
            ],
            const: false,
            noexcept: false,
            attributes: [],
        },
        // void assign_member(void * parent, obj<AGCobject> * p_lhs, obj<AGCobject & rhs);
        {
            name: "assign_member",
            doc: [
                "Assign pointer @p p_lhs to destination @p rhs, within parent allocation @p parent",
                "DEPRECATED. Only used in MockCollector for gc unit test",
                "",
                "Require: gc not in progress",
            ],
            return_type: "void",
            args: [
                {type: "void *", name: "parent"},
                {type: "obj<AGCObject> *", name: "p_lhs"},
                {type: "obj<AGCObject> &", name: "rhs"},
            ],
            const: false,
            noexcept: false,
            attributes: [],
        },
        // void alloc_copy(void * src)
        {
            name: "alloc_copy",
            doc: [
                "allocate copy of source object at address @p src.",
                "Source must be owned by this collector.",
                "Increments object age"
            ],
            return_type: "void *",
            args: [
                {type: "std::byte *", name: "src"},
            ],
            const: false,
            noexcept: false,
            attributes: [],
        },
    ],
    router_facet_explicit_content: [
        "/** convenience template for gc object copy **/",
        "template <typename T>",
        "void * alloc_copy_for(const T * src) noexcept {",
        "    return O::iface()->alloc_copy(O::data(), (std::byte *)const_cast<T *>(src));",
        "}",
        "",
        "/** convenience template for move-constructible T (this is common) **/",
        "template <typename T>",
        "T * std_move_for(T * src) noexcept {",
        "    void * mem = this->alloc_copy_for(src);",
        "    if (mem) {",
        "        return new (mem) T(std::move(*src));",
        "    }",
        "    return nullptr;",
        "}",
        "",
        "/** forward faceted object pointer in place. Defined in GCObject.hpp to avoid #include cycle **/",
        "template <typename DRepr>",
        "void forward_inplace(obj<AGCObject,DRepr> * p_obj);",
        "",
        "/** another convenience template for forwarding.",
        " *  Defined in RGCObject.hpp to avoid #include cycle.",
        "**/",
        "template <typename DRepr>",
        "void forward_inplace(DRepr ** pp_repr);",
        "",
        "/** convenience template where pointer requires pivot **/",
        "template <typename AFacet, typename DRepr>",
        "requires (!std::is_same_v<AFacet, AGCObject>)",
        "void forward_pivot_inplace(obj<AFacet,DRepr> * p_obj);",
        "",
        "/** add root @p p_root **/",
        "template<typename DRepr>",
        "void add_gc_root(obj<AGCObject, DRepr> * p_root) {",
        "    O::iface()->add_gc_root_poly(O::data(), (obj<AGCObject> *)p_root);",
        "}",
        "",
        "/** remove root @p p_root **/",
        "template <typename DRepr>",
        "void remove_gc_root(obj<AGCObject, DRepr> * p_root) {",
        "    O::iface()->remove_gc_root_poly(O::data(), (obj<AGCObject> *)p_root);",
        "}",
    ],
}
