Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
.Rhistory
.RData
docs
compile_commands.json
30 changes: 26 additions & 4 deletions src/inspect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ class GrowableList {
}
};

SEXP obj_children_(SEXP x, std::map<SEXP, int>& seen, double max_depth, Expand expand);
SEXP collect_attribs(SEXP x);
bool is_namespace(cpp11::environment env);
SEXP obj_children_(SEXP x, std::map<SEXP, int>& seen, double max_depth, Expand expand);

bool is_altrep(SEXP x) {
#if defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0)
Expand Down Expand Up @@ -320,9 +321,10 @@ SEXP obj_children_(
}
}

// CHARSXPs have fake attriibutes
if (max_depth > 0 && TYPEOF(x) != CHARSXP && !Rf_isNull(ATTRIB(x))) {
recurse(&children, seen, "_attrib", ATTRIB(x), max_depth, expand);
// CHARSXPs have fake attributes so don't inspecct them
if (max_depth > 0 && TYPEOF(x) != CHARSXP && ANY_ATTRIB(x)) {
recurse(&children, seen, "_attrib", PROTECT(collect_attribs(x)), max_depth, expand);
UNPROTECT(1);
}

SEXP out = PROTECT(children.vector());
Expand All @@ -335,6 +337,26 @@ SEXP obj_children_(
return out;
}

// Collect attributes into a pairlist
SEXP collect_attribs(SEXP x) {
SEXP sentinel = PROTECT(Rf_cons(R_NilValue, R_NilValue));
SEXP tail = sentinel;

R_mapAttrib(x, [](SEXP tag, SEXP val, void* data) -> SEXP {
SEXP* tail = (SEXP*)data;

SEXP node = Rf_cons(val, R_NilValue);
SETCDR(*tail, node);
SET_TAG(node, tag);

*tail = node;
return NULL;
}, &tail);

UNPROTECT(1);
return CDR(sentinel);
}


[[cpp11::register]]
cpp11::list obj_inspect_(SEXP x,
Expand Down
11 changes: 9 additions & 2 deletions src/size.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,15 @@ double obj_size_tree(SEXP x,
#endif

// CHARSXPs have fake attributes
if (TYPEOF(x) != CHARSXP )
size += obj_size_tree(ATTRIB(x), base_env, sizeof_node, sizeof_vector, seen, depth + 1);
if (TYPEOF(x) != CHARSXP && ANY_ATTRIB(x)) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have collect_attribs() should we just use it here? Probably a little bit less efficient but that's unlikely to matter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!

SEXP attribs = PROTECT(collect_attribs(x));
for (SEXP node = attribs; node != R_NilValue; node = CDR(node)) {
size += sizeof_node;
size += obj_size_tree(TAG(node), base_env, sizeof_node, sizeof_vector, seen, depth + 1);
size += obj_size_tree(CAR(node), base_env, sizeof_node, sizeof_vector, seen, depth + 1);
}
UNPROTECT(1);
}

switch (TYPEOF(x)) {
// Vectors -------------------------------------------------------------------
Expand Down
33 changes: 33 additions & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,37 @@ static inline
SEXP R_ParentEnv(SEXP x) {
return ENCLOS(x);
}

static inline
int ANY_ATTRIB(SEXP x) {
return ATTRIB(x) != R_NilValue;
}
#endif

#if R_VERSION < R_Version(4, 6, 0)
// Polyfill for R_mapAttrib(), available in R >= 4.6.0.
// Pulled exactly as-is from R:
// https://github.com/r-devel/r-svn/blob/a39f4a28848fd02a1310b455353a871f2bb1965b/src/main/attrib.c#L2014
// https://github.com/r-devel/r-svn/blob/a39f4a28848fd02a1310b455353a871f2bb1965b/doc/manual/R-exts.texi#L17920
static inline
SEXP R_mapAttrib(SEXP x, SEXP (*FUN)(SEXP, SEXP, void *), void *data) {
PROTECT_INDEX api;
SEXP a = ATTRIB(x);
SEXP val = NULL;

PROTECT_WITH_INDEX(a, &api);
while (a != R_NilValue) {
SEXP tag = PROTECT(TAG(a));
SEXP attr = PROTECT(CAR(a));
val = FUN(tag, attr, data);
UNPROTECT(2);
if (val != NULL)
break;
REPROTECT(a = CDR(a), api);
}
UNPROTECT(1);
return val;
}
#endif

SEXP collect_attribs(SEXP x);