Skip to content

Commit

Permalink
groot/rdict: proper handling of 'This' streamers
Browse files Browse the repository at this point in the history
'This' streamers are used to extract the type argument of templates.
e.g.:
 class MyVector: public std::vector<Foo> {...};
would be encoded as a TStreamerInfo named 'MyVector' and an element
named "This" with a title "<Foo> Used to call ...".

This technique seems to be used to properly extract 'Foo'.
This seems to be also applied for other containers. (vector, deque, ...)
  • Loading branch information
sbinet committed Feb 16, 2022
1 parent 0a85f50 commit 34d6347
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 22 deletions.
18 changes: 18 additions & 0 deletions groot/rdict/rwstreamer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3252,6 +3252,24 @@ func TestRWStream(t *testing.T) {
},
},
},
{
name: "rmeta-stl-vector<set<int>>",
ptr: &struct {
F [][]int32
}{[][]int32{{1}, {2, 3}}},
si: &StreamerInfo{
named: *rbase.NewNamed("T", "T"),
objarr: rcont.NewObjArray(),
elems: []rbytes.StreamerElement{
NewCxxStreamerSTL(Element{
Name: *rbase.NewNamed("This", "Used to call the proper TStreamerInfo case"),
Type: rmeta.STL,
MaxIdx: [5]int32{0, 0, 0, 0, 0},
EName: "vector<set<int> >",
}.New(), rmeta.STLvector, rmeta.Object),
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.skip {
Expand Down
44 changes: 38 additions & 6 deletions groot/rdict/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,19 @@ func TypeFromSE(ctx rbytes.StreamerInfoContext, se rbytes.StreamerElement) (refl
case rmeta.STLvector, rmeta.STLlist, rmeta.STLdeque:
var (
ct = se.ContainedType()
ename = rmeta.CxxTemplateFrom(se.TypeName()).Args[0]
typevers = int16(-1)
elt, err = typeFromTypeName(ctx, ename, typevers, ct, se, 1)
ename string
)
switch {
case hasThisHandling(se):
ename = se.Title()
ename = ename[:strings.Index(ename, "> Used to call the proper TStreamerInfo case")+1]
ename = strings.TrimSpace(ename)
ename = rmeta.CxxTemplateFrom("Type" + ename).Args[0]
default:
ename = rmeta.CxxTemplateFrom(se.TypeName()).Args[0]
}
elt, err := typeFromTypeName(ctx, ename, typevers, ct, se, 1)
if err != nil {
return nil, fmt.Errorf("rdict: could not create type for %q: %w", se.TypeName(), err)
}
Expand All @@ -208,8 +217,17 @@ func TypeFromSE(ctx rbytes.StreamerInfoContext, se rbytes.StreamerElement) (refl
ct = se.ContainedType()
typename = se.TypeName()
typevers = int16(-1)
kname = rmeta.CxxTemplateFrom(se.TypeName()).Args[0]
kname string
)
switch {
case hasThisHandling(se):
kname = se.Title()
kname = kname[:strings.Index(kname, "> Used to call the proper TStreamerInfo case")+1]
kname = strings.TrimSpace(kname)
kname = rmeta.CxxTemplateFrom("Type" + kname).Args[0]
default:
kname = rmeta.CxxTemplateFrom(typename).Args[0]
}

key, err := typeFromTypeName(ctx, kname, typevers, ct, se, 1)
if err != nil {
Expand All @@ -224,10 +242,20 @@ func TypeFromSE(ctx rbytes.StreamerInfoContext, se rbytes.StreamerElement) (refl
ct = se.ContainedType()
typename = se.TypeName()
typevers = int16(-1)
enames = rmeta.CxxTemplateFrom(se.TypeName()).Args
kname = enames[0]
vname = enames[1]
enames []string
)
switch {
case hasThisHandling(se):
ename := se.Title()
ename = ename[1:] // drop leading '<'
ename = ename[:strings.Index(ename, "> Used to call the proper TStreamerInfo case")]
ename = strings.TrimSpace(ename)
enames = rmeta.CxxTemplateFrom(ename).Args
default:
enames = rmeta.CxxTemplateFrom(typename).Args
}
kname := enames[0]
vname := enames[1]

key, err := typeFromTypeName(ctx, kname, typevers, ct, se, 1)
if err != nil {
Expand Down Expand Up @@ -560,3 +588,7 @@ func hasStdPrefix(typename string, ps ...string) bool {
}
return false
}

func hasThisHandling(se rbytes.StreamerElement) bool {
return se.Name() == "This" && strings.HasPrefix(se.Title(), "<")
}
44 changes: 28 additions & 16 deletions groot/rdict/type_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,23 @@ func TestTypeFromSI(t *testing.T) {
ROOT_second float32 `groot:"second"`
})(nil)).Elem(),
},
{
name: "vector<int>",
si: rdict.NewCxxStreamerInfo("vector<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "vector<int>",
}.New(), rmeta.STLvector, rmeta.Object),
}),
want: reflect.TypeOf((*[]int32)(nil)).Elem(),
},
{
name: "list<int>",
si: rdict.NewCxxStreamerInfo("list<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "list<int>",
Expand All @@ -220,7 +232,7 @@ func TestTypeFromSI(t *testing.T) {
name: "deque<int>",
si: rdict.NewCxxStreamerInfo("deque<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "deque<int>",
Expand All @@ -232,7 +244,7 @@ func TestTypeFromSI(t *testing.T) {
name: "set<int>",
si: rdict.NewCxxStreamerInfo("set<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "set<int>",
Expand All @@ -244,7 +256,7 @@ func TestTypeFromSI(t *testing.T) {
name: "multiset<int>",
si: rdict.NewCxxStreamerInfo("multiset<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "set<int>",
Expand All @@ -256,7 +268,7 @@ func TestTypeFromSI(t *testing.T) {
name: "unordered_set<int>",
si: rdict.NewCxxStreamerInfo("unordered_set<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "unordered_set<int>",
Expand All @@ -268,7 +280,7 @@ func TestTypeFromSI(t *testing.T) {
name: "unordered_multiset<int>",
si: rdict.NewCxxStreamerInfo("unordered_multiset<int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<int> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "unordered_multiset<int>",
Expand All @@ -280,7 +292,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<int,float>",
si: rdict.NewCxxStreamerInfo("map<int,float>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,float>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<int,float>",
Expand All @@ -292,7 +304,7 @@ func TestTypeFromSI(t *testing.T) {
name: "multimap<int,float>",
si: rdict.NewCxxStreamerInfo("multimap<int,float>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,float>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "multimap<int,float>",
Expand All @@ -304,7 +316,7 @@ func TestTypeFromSI(t *testing.T) {
name: "unordered_map<int,float>",
si: rdict.NewCxxStreamerInfo("unordered_map<int,float>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,float>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "unordered_map<int,float>",
Expand All @@ -316,7 +328,7 @@ func TestTypeFromSI(t *testing.T) {
name: "unordered_multimap<int,float>",
si: rdict.NewCxxStreamerInfo("unordered_multimap<int,float>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,float>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "unordered_multimap<int,float>",
Expand All @@ -328,7 +340,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<int,string>",
si: rdict.NewCxxStreamerInfo("map<int,string>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,string>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<int,string>",
Expand All @@ -340,7 +352,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<int,TNamed>",
si: rdict.NewCxxStreamerInfo("map<int,TNamed>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,TNamed>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<int,TNamed>",
Expand All @@ -352,7 +364,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<TNamed,int>",
si: rdict.NewCxxStreamerInfo("map<TNamed,int>", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<TNamed,int>> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<TNamed,int>",
Expand All @@ -364,7 +376,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<int,vector<TNamed> >",
si: rdict.NewCxxStreamerInfo("map<int,vector<TNamed> >", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,vector<TNamed> >> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<int,vector<TNamed> >",
Expand All @@ -376,7 +388,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<int,vector<string> >",
si: rdict.NewCxxStreamerInfo("map<int,vector<string> >", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,vector<string> >> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<int,vector<string> >",
Expand All @@ -388,7 +400,7 @@ func TestTypeFromSI(t *testing.T) {
name: "map<int,map<int,vector<string> > >",
si: rdict.NewCxxStreamerInfo("map<int,map<int,vector<string> > >", 1, 0, []rbytes.StreamerElement{
rdict.NewCxxStreamerSTL(rdict.Element{
Name: *rbase.NewNamed("This", ""),
Name: *rbase.NewNamed("This", "<pair<int,map<int,vector<string> > >> Used to call the proper TStreamerInfo case"),
Type: rmeta.Streamer,
Size: 48,
EName: "map<int,map<int,vector<string> > >",
Expand Down

0 comments on commit 34d6347

Please sign in to comment.