@@ -126542,7 +126542,7 @@ class TDrawSelector extends TSelector {
126542126542 this.leaf = args.leaf;
126543126543
126544126544 // branch object remains, therefore we need to copy fields to see them all
126545- this.copy_fields = (( args.branch.fLeaves?.arr.length > 1) || args.branch.fBranches?.arr.length) && !args.leaf;
126545+ this.copy_fields = args.copy_fields ?? ((( args.branch.fLeaves?.arr.length > 1) || args.branch.fBranches?.arr.length) && !args.leaf) ;
126546126546
126547126547 this.addBranch(branch, 'br0', args.direct_branch); // add branch
126548126548
@@ -178256,9 +178256,20 @@ class RNTupleDescriptorBuilder {
178256178256 }
178257178257 }
178258178258
178259+ /** @summary Return all childs of specified field */
178260+ findChildFields(field) {
178261+ const indx = this.fieldDescriptors.indexOf(field), res = [];
178262+ for (let n = 0; n < this.fieldDescriptors.length; ++n) {
178263+ const fld = this.fieldDescriptors[n];
178264+ if ((fld !== field) && (fld.parentFieldId === indx))
178265+ res.push(fld);
178266+ }
178267+ return res;
178268+ }
178269+
178259178270 /** @summary Return array of columns for specified field */
178260- findColumns(name ) {
178261- const res = [], field = this.findField(name) ;
178271+ findColumns(field ) {
178272+ const res = [];
178262178273 if (!field)
178263178274 return res;
178264178275 for (const colDesc of this.columnDescriptors) {
@@ -178268,6 +178279,7 @@ class RNTupleDescriptorBuilder {
178268178279 return res;
178269178280 }
178270178281
178282+
178271178283} // class RNTupleDescriptorBuilder
178272178284
178273178285
@@ -178359,11 +178371,13 @@ class ReaderItem {
178359178371 this.page = -1; // current page for the reading
178360178372 this.name = name;
178361178373 this.sz = 0;
178374+ this.simple = true;
178362178375
178363178376 // special handling of split types
178364178377 if ((this.coltype >= ENTupleColumnType.kSplitInt16) && (this.coltype <= ENTupleColumnType.kSplitIndex64)) {
178365178378 this.splittype = this.coltype;
178366178379 this.coltype -= (ENTupleColumnType.kSplitInt16 - ENTupleColumnType.kInt16);
178380+ this.simple = false;
178367178381 }
178368178382 }
178369178383
@@ -178403,8 +178417,13 @@ class ReaderItem {
178403178417 }
178404178418 }
178405178419
178406- /** @summary Simple column which fixed element size */
178407- is_simple() { return this.sz > 0; }
178420+ /** @summary Simple column with fixed element size - no vectors, no strings */
178421+ is_simple() { return this.sz > 0 && this.simple; }
178422+
178423+ set_simple(flag) {
178424+ this.simple = flag;
178425+ this.item1?.set_simple(flag);
178426+ }
178408178427
178409178428 assignReadFunc() {
178410178429 switch (this.coltype) {
@@ -178508,13 +178527,17 @@ class ReaderItem {
178508178527 }
178509178528
178510178529 /** @summary identify if this item used as offset for std::string or similar */
178511- is_offset_item() { return this.item1 ; }
178530+ is_offset_item() { return ( this.func0 && this.shift0) || (this.shiftn && this.funcn) ; }
178512178531
178532+ /** @summary implements reading of std::string where item1 provides offsets */
178513178533 assignStringReader(item1) {
178514178534 this.item1 = item1;
178515178535 this.off0 = 0;
178516178536 this.$tgt = {};
178517178537
178538+ this.simple = false;
178539+ // for plain string one can read offsets
178540+
178518178541 item1.func0 = item1.func;
178519178542 item1.shift0 = item1.shift;
178520178543
@@ -178535,14 +178558,55 @@ class ReaderItem {
178535178558
178536178559 this.shift = function(entries) {
178537178560 if (entries > 0) {
178538- this.item1.shift0(entries);
178561+ this.item1.shift0(entries - 1 );
178539178562 this.item1.func0(this.$tgt);
178540178563 this.off0 = Number(this.$tgt[this.name]);
178541178564 this.shift_o(this.off0);
178542178565 }
178543178566 };
178544178567 }
178545178568
178569+ /** @summary implement reading of std::vector where itemv provides element reading */
178570+ assignVectorReader(itemv) {
178571+ this.itemv = itemv;
178572+ this.offv0 = 0;
178573+
178574+ itemv.funcv = itemv.func;
178575+ itemv.shiftv = itemv.shift;
178576+ // assign noop
178577+ itemv.func = itemv.shift = () => {};
178578+
178579+ // item itself can remain simple
178580+ itemv.set_simple(false);
178581+
178582+ // remember own read function - they need to be used
178583+ this.funcn = this.func;
178584+ this.shiftn = this.shift;
178585+
178586+ this.func = function(tgtobj) {
178587+ const arr = [], tmp = {};
178588+ this.funcn(tmp);
178589+ const offv = Number(tmp[this.name]);
178590+ let len = offv - this.offv0;
178591+ while (len-- > 0) {
178592+ this.itemv.funcv(tmp);
178593+ arr.push(tmp[this.name]);
178594+ }
178595+ tgtobj[this.name] = arr;
178596+ this.offv0 = offv;
178597+ };
178598+
178599+ this.shift = function(entries) {
178600+ if (entries > 0) {
178601+ const tmp = {};
178602+ this.shiftn(entries - 1);
178603+ this.funcn(tmp);
178604+ this.offv0 = Number(tmp[this.name]);
178605+ this.itemv.shiftv(this.offv0);
178606+ }
178607+ };
178608+ }
178609+
178546178610 collectPages(cluster_locations, dataToRead, itemsToRead, pagesToRead, emin, emax, elist) {
178547178611 const pages = cluster_locations[this.id].pages;
178548178612
@@ -178552,13 +178616,13 @@ class ReaderItem {
178552178616 for (let p = 0; p < pages.length; ++p) {
178553178617 const page = pages[p],
178554178618 e1 = e0 + Number(page.numElements),
178555- margin = this.is_offset_item() ? 1 : 0; // offset for previous entry has to be read as well
178556-
178619+ margin = this.is_offset_item() ? 1 : 0, // offset for previous entry has to be read as well
178620+ is_inside = (e, beg, end) => (e >= beg) && (e < end + margin);
178557178621 let is_entries_inside = false;
178558178622 if (elist?.length)
178559- elist.forEach(e => { is_entries_inside ||= (e >= e0) && (e - margin < e1); });
178623+ elist.forEach(e => { is_entries_inside ||= is_inside(e, e0, e1); });
178560178624 else
178561- is_entries_inside = ((e0 >= emin - margin) && (e0 < emax)) || ((e1 > emin - margin) && (e1 <= emax) );
178625+ is_entries_inside = is_inside(e0, emin, emax) || is_inside(e1, emin, emax) || is_inside( emin, e0, e1) || is_inside(emax, e0, e1 );
178562178626
178563178627 if (!this.is_simple() || is_entries_inside) {
178564178628 itemsToRead.push(this);
@@ -178707,29 +178771,46 @@ async function rntupleProcess(rntuple, selector, args = {}) {
178707178771 });
178708178772 }
178709178773
178774+ function addFieldReading(field, tgtname) {
178775+ const columns = rntuple.builder.findColumns(field);
178776+ if (!columns?.length)
178777+ throw new Error(`No columns found for field '${field.fieldName}' in RNTuple`);
178778+
178779+ let item = new ReaderItem(columns[0], tgtname);
178780+ item.assignReadFunc();
178781+ handle.arr.push(item);
178782+
178783+ if ((columns.length === 2) && (field.typeName === 'std::string')) {
178784+ const items = new ReaderItem(columns[1], tgtname);
178785+ items.assignStringReader(item);
178786+ handle.arr.push(items);
178787+ item = items; // second item performs complete reading of the string
178788+ }
178789+
178790+ const childs = rntuple.builder.findChildFields(field);
178791+ if ((childs.length === 1) && (field.typeName.indexOf('std::vector') === 0)) {
178792+ const itemv = addFieldReading(childs[0], tgtname);
178793+ item.assignVectorReader(itemv);
178794+ }
178795+
178796+ return item;
178797+ }
178798+
178710178799 return readHeaderFooter(rntuple).then(res => {
178711178800 if (!res)
178712178801 throw new Error('Not able to read header for the RNtuple');
178713178802
178714178803 for (let i = 0; i < selector.numBranches(); ++i) {
178715- const name = getSelectorFieldName(selector, i);
178804+ const name = getSelectorFieldName(selector, i),
178805+ tgtname = selector.nameOfBranch(i);
178716178806 if (!name)
178717178807 throw new Error(`Not able to extract name for field ${i}`);
178718178808
178719- const columns = rntuple.builder.findColumns(name);
178720- if (!columns?.length)
178721- throw new Error(`No columns found for field '${name}' in RNTuple`);
178722-
178723- const tgtname = selector.nameOfBranch(i),
178724- item = new ReaderItem(columns[0], tgtname);
178725- item.assignReadFunc();
178726- handle.arr.push(item);
178809+ const field = rntuple.builder.findField(name);
178810+ if (!field)
178811+ throw new Error(`Field ${name} not found`);
178727178812
178728- if (columns.length === 2) {
178729- const item2 = new ReaderItem(columns[1], tgtname);
178730- item2.assignStringReader(item);
178731- handle.arr.push(item2);
178732- }
178813+ addFieldReading(field, tgtname);
178733178814 }
178734178815
178735178816 // calculate number of entries
@@ -178877,13 +178958,15 @@ async function drawRNTuple(dom, obj, opt) {
178877178958 const args = {};
178878178959 let tuple;
178879178960
178880- if (obj?.$tuple) {
178961+ if (obj?.$tuple && obj.$field ) {
178881178962 // case of fictional ROOT::RNTupleField
178882178963 tuple = obj.$tuple;
178883178964 args.expr = obj._name;
178884- if (isStr(opt) && opt.indexOf('dump') === 0)
178965+ if (isStr(opt) && opt.indexOf('dump') === 0) {
178885178966 args.expr += '>>' + opt;
178886- else if (opt)
178967+ args.branch = obj.$field;
178968+ args.copy_fields = false; // no need to copy fields, reading is simple
178969+ } else if (opt)
178887178970 args.expr += opt;
178888178971 } else {
178889178972 tuple = obj;
0 commit comments