Skip to content

Commit

Permalink
groot/{rdict,rmeta}: introduce CxxTemplate, streamline template parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
sbinet committed Feb 11, 2022
1 parent be7ddfa commit d23d2f4
Show file tree
Hide file tree
Showing 9 changed files with 619 additions and 562 deletions.
134 changes: 1 addition & 133 deletions groot/rdict/rdict.go
Expand Up @@ -1065,139 +1065,7 @@ func (tss *StreamerSTL) Class() string {
}

func (tss *StreamerSTL) ElemTypeName() []string {
switch tss.vtype {
case rmeta.STLvector:
return parseStdVector(tss.ename)
case rmeta.STLmap:
return parseStdMap(tss.ename)
case rmeta.STLbitset:
return parseStdBitset(tss.ename)
default:
panic("not implemented")
}
}

func parseStdVector(tmpl string) []string {
v := tmpl
switch {
case strings.HasSuffix(v, ">"):
v = v[:len(v)-1]
default:
panic(fmt.Errorf("invalid std::vector container name (missing '>'): %q", tmpl))
}
switch {
case strings.HasPrefix(v, "vector<"):
v = v[len("vector<"):]
case strings.HasPrefix(v, "std::vector<"):
v = v[len("std::vector<"):]
default:
panic(fmt.Errorf("invalid std::vector container name (missing 'vector<'): %q", tmpl))
}
var (
keyT string
allT string
depth int
coms []int
)
if strings.Contains(v, ",") {
for i, b := range []byte(v) {
switch b {
case '<':
depth++
case '>':
depth--
case ',':
if depth == 0 {
coms = append(coms, i)
}
}
}
}
switch len(coms) {
case 0:
keyT = v
case 1:
keyT = v[:coms[0]]
allT = v[coms[0]+1:]
default:
panic(fmt.Errorf("invalid std::vector template %q", tmpl))
}
keyT = strings.TrimSpace(keyT)
if keyT == "" {
panic(fmt.Errorf("invalid std::vector container name (missing element type): %q", tmpl))
}
allT = strings.TrimSpace(allT)
switch allT {
case "":
return []string{keyT}
default:
return []string{keyT, allT}
}
}

func parseStdMap(tmpl string) []string {
v := tmpl
switch {
case strings.HasSuffix(v, ">"):
v = v[:len(v)-1]
default:
panic(fmt.Errorf("invalid std::map container name (missing '>'): %q", tmpl))
}
switch {
case strings.HasPrefix(v, "map<"):
v = v[len("map<"):]
case strings.HasPrefix(v, "std::map<"):
v = v[len("std::map<"):]
default:
panic(fmt.Errorf("invalid std::map container name (missing 'map<'): %q", tmpl))
}
var (
keyT string
valT string
cmpT string
depth int
coms []int
)
for i, b := range []byte(v) {
switch b {
case '<':
depth++
case '>':
depth--
case ',':
if depth == 0 {
coms = append(coms, i)
}
}
}
switch len(coms) {
case 1:
keyT = v[:coms[0]]
valT = v[coms[0]+1:]
case 2:
keyT = v[:coms[0]]
valT = v[coms[0]+1 : coms[1]]
cmpT = v[coms[1]+1:]
default:
panic(fmt.Errorf("invalid std::map template %q", tmpl))
}
keyT = strings.TrimSpace(keyT)
valT = strings.TrimSpace(valT)
cmpT = strings.TrimSpace(cmpT)
switch cmpT {
case "":
return []string{keyT, valT}
default:
return []string{keyT, valT, cmpT}
}
}

func parseStdBitset(tmpl string) []string {
enames := rmeta.CxxTemplateArgsOf(tmpl)
if len(enames) > 1 {
panic(fmt.Errorf("invalid std::bitset template %q", tmpl))
}
return enames
return rmeta.CxxTemplateFrom(tss.ename).Args
}

func (tss *StreamerSTL) ContainedType() rmeta.Enum {
Expand Down
165 changes: 36 additions & 129 deletions groot/rdict/rdict_test.go
Expand Up @@ -205,156 +205,63 @@ func TestElementGetRange(t *testing.T) {
}
}

func TestParseStdContainers(t *testing.T) {
func TestStreamerSTLElemTypeName(t *testing.T) {
for _, tc := range []struct {
name string
parse func(string) []string
want []string
panics string
typ rmeta.ESTLType
name string
want []string
}{
// std::vector
{
name: "vector<int>",
parse: parseStdVector,
want: []string{"int"},
typ: rmeta.STLvector,
name: "vector<T>",
want: []string{"T"},
},
{
name: "std::vector<int>",
parse: parseStdVector,
want: []string{"int"},
typ: rmeta.STLlist,
name: "list<T>",
want: []string{"T"},
},
{
name: "vector<vector<int>>",
parse: parseStdVector,
want: []string{"vector<int>"},
typ: rmeta.STLdeque,
name: "deque<T>",
want: []string{"T"},
},
{
name: "vector<int,allocator<int>>",
parse: parseStdVector,
want: []string{"int", "allocator<int>"},
typ: rmeta.STLset,
name: "set<T>",
want: []string{"T"},
},
{
name: "vector<map<int,long int>>",
parse: parseStdVector,
want: []string{"map<int,long int>"},
typ: rmeta.STLunorderedset,
name: "unordered_set<T>",
want: []string{"T"},
},
{
name: "vector<int",
parse: parseStdVector,
panics: `invalid std::vector container name (missing '>'): "vector<int"`,
typ: rmeta.STLmap,
name: "map<K,V>",
want: []string{"K", "V"},
},
{
name: "xvector<int>",
parse: parseStdVector,
panics: `invalid std::vector container name (missing 'vector<'): "xvector<int>"`,
typ: rmeta.STLunorderedmap,
name: "unordered_map<K,V>",
want: []string{"K", "V"},
},
{
name: "vector<>",
parse: parseStdVector,
panics: `invalid std::vector container name (missing element type): "vector<>"`,
},
{
name: "vector<t1,t2,t3>",
parse: parseStdVector,
panics: `invalid std::vector template "vector<t1,t2,t3>"`,
},
// std::map
{
name: "map< int , int >",
parse: parseStdMap,
want: []string{"int", "int"},
},
{
name: "map<int,int>",
parse: parseStdMap,
want: []string{"int", "int"},
},
{
name: "std::map<int,int>",
parse: parseStdMap,
want: []string{"int", "int"},
},
{
name: "map<int,int>",
parse: parseStdMap,
want: []string{"int", "int"},
},
{
name: "map<int,string>",
parse: parseStdMap,
want: []string{"int", "string"},
},
{
name: "map<int,vector<int>>",
parse: parseStdMap,
want: []string{"int", "vector<int>"},
},
{
name: "map<int,vector<int> >",
parse: parseStdMap,
want: []string{"int", "vector<int>"},
},
{
name: "map<int,map<string,int> >",
parse: parseStdMap,
want: []string{"int", "map<string,int>"},
},
{
name: "map<map<string,int>, int>",
parse: parseStdMap,
want: []string{"map<string,int>", "int"},
},
{
name: "map<map<string,int>, map<int,string>>",
parse: parseStdMap,
want: []string{"map<string,int>", "map<int,string>"},
},
{
name: "map<long int,long int>",
parse: parseStdMap,
want: []string{"long int", "long int"},
},
{
name: "map<long int, vector<long int>, allocator<pair<const long int, vector<long int>>>",
parse: parseStdMap,
want: []string{"long int", "vector<long int>", "allocator<pair<const long int, vector<long int>>"},
},
{
name: "map<k,v",
parse: parseStdMap,
panics: `invalid std::map container name (missing '>'): "map<k,v"`,
},
{
name: "map<k,v,a,XXX>",
parse: parseStdMap,
panics: `invalid std::map template "map<k,v,a,XXX>"`,
},
{
name: "map<>",
parse: parseStdMap,
panics: `invalid std::map template "map<>"`,
},
{
name: "xmap<k,v>",
parse: parseStdMap,
panics: `invalid std::map container name (missing 'map<'): "xmap<k,v>"`,
typ: rmeta.STLbitset,
name: "bitset<8>",
want: []string{"8"},
},
} {
t.Run(tc.name, func(t *testing.T) {
if tc.panics != "" {
defer func() {
err := recover()
if err == nil {
t.Fatalf("expected a panic (%s)", tc.panics)
}
if got, want := err.(error).Error(), tc.panics; got != want {
t.Fatalf("invalid panic message: got=%s, want=%s", got, want)
}
}()
ts := StreamerSTL{
StreamerElement: StreamerElement{
ename: tc.name,
},
vtype: tc.typ,
}
got := tc.parse(tc.name)
if !reflect.DeepEqual(got, tc.want) {
t.Fatalf("got=%q, want=%q", got, tc.want)
got := ts.ElemTypeName()
if got, want := got, tc.want; !reflect.DeepEqual(got, want) {
t.Fatalf("invalid ElemTypeName:\ngot= %q\nwant=%q", got, want)
}
})
}
Expand Down

0 comments on commit d23d2f4

Please sign in to comment.