|  | /* Copyright (C) 2021 Free Software Foundation, Inc. | 
|  | Contributed by Oracle. | 
|  |  | 
|  | This file is part of GNU Binutils. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program; if not, write to the Free Software | 
|  | Foundation, 51 Franklin Street - Fifth Floor, Boston, | 
|  | MA 02110-1301, USA.  */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "IndexMap2D.h" | 
|  | #include "DbeSession.h" | 
|  | #include "FilterExp.h" | 
|  | #include "Table.h" | 
|  | #include "util.h" | 
|  | #include "i18n.h" | 
|  |  | 
|  | char * | 
|  | get_prof_data_type_name (int t) | 
|  | { | 
|  | switch (t) | 
|  | { | 
|  | case DATA_SAMPLE:   return NTXT("PROFDATA_TYPE_SAMPLE"); | 
|  | case DATA_GCEVENT:  return NTXT("PROFDATA_TYPE_GCEVENT"); | 
|  | case DATA_HEAPSZ:   return NTXT("PROFDATA_TYPE_HEAPSZ"); | 
|  | case DATA_CLOCK:    return NTXT("PROFDATA_TYPE_CLOCK"); | 
|  | case DATA_HWC:      return NTXT("PROFDATA_TYPE_HWC"); | 
|  | case DATA_SYNCH:    return NTXT("PROFDATA_TYPE_SYNCH"); | 
|  | case DATA_HEAP:     return NTXT("PROFDATA_TYPE_HEAP"); | 
|  | case DATA_OMP:      return NTXT("PROFDATA_TYPE_OMP"); | 
|  | case DATA_OMP2:     return NTXT("PROFDATA_TYPE_OMP2"); | 
|  | case DATA_OMP3:     return NTXT("PROFDATA_TYPE_OMP3"); | 
|  | case DATA_OMP4:     return NTXT("PROFDATA_TYPE_OMP4"); | 
|  | case DATA_OMP5:     return NTXT("PROFDATA_TYPE_OMP5"); | 
|  | case DATA_IOTRACE:  return NTXT("PROFDATA_TYPE_IOTRACE"); | 
|  | default: abort (); | 
|  | return NTXT ("PROFDATA_TYPE_ERROR"); | 
|  | } | 
|  | } | 
|  |  | 
|  | char * | 
|  | get_prof_data_type_uname (int t) | 
|  | { | 
|  | switch (t) | 
|  | { | 
|  | case DATA_SAMPLE:   return GTXT("Process-wide Resource Utilization"); | 
|  | case DATA_GCEVENT:  return GTXT("Java Garbage Collection Events"); | 
|  | case DATA_HEAPSZ:   return GTXT("Heap Size"); | 
|  | case DATA_CLOCK:    return GTXT("Clock Profiling"); | 
|  | case DATA_HWC:      return GTXT("HW Counter Profiling"); | 
|  | case DATA_SYNCH:    return GTXT("Synchronization Tracing"); | 
|  | case DATA_HEAP:     return GTXT("Heap Tracing"); | 
|  | case DATA_OMP:      return GTXT("OpenMP Profiling"); | 
|  | case DATA_OMP2:     return GTXT("OpenMP Profiling"); | 
|  | case DATA_OMP3:     return GTXT("OpenMP Profiling"); | 
|  | case DATA_OMP4:     return GTXT("OpenMP Profiling"); | 
|  | case DATA_OMP5:     return GTXT("OpenMP Profiling"); | 
|  | case DATA_IOTRACE:  return GTXT("IO Tracing"); | 
|  | default: abort (); | 
|  | return NTXT ("PROFDATA_TYPE_ERROR"); | 
|  | } | 
|  | } | 
|  |  | 
|  | int assert_level = 0; // set to 1 to bypass problematic asserts | 
|  |  | 
|  | #define ASSERT_SKIP (assert_level) | 
|  |  | 
|  | /* | 
|  | *    class PropDescr | 
|  | */ | 
|  |  | 
|  | PropDescr::PropDescr (int _propID, const char *_name) | 
|  | { | 
|  | propID = _propID; | 
|  | name = strdup (_name ? _name : NTXT ("")); | 
|  | uname = NULL; | 
|  | vtype = TYPE_NONE; | 
|  | flags = 0; | 
|  | stateNames = NULL; | 
|  | stateUNames = NULL; | 
|  | } | 
|  |  | 
|  | PropDescr::~PropDescr () | 
|  | { | 
|  | free (name); | 
|  | free (uname); | 
|  | if (stateNames) | 
|  | { | 
|  | stateNames->destroy (); | 
|  | delete stateNames; | 
|  | } | 
|  | if (stateUNames) | 
|  | { | 
|  | stateUNames->destroy (); | 
|  | delete stateUNames; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | PropDescr::addState (int value, const char *stname, const char *stuname) | 
|  | { | 
|  | if (value < 0 || stname == NULL) | 
|  | return; | 
|  | if (stateNames == NULL) | 
|  | stateNames = new Vector<char*>; | 
|  | stateNames->store (value, strdup (stname)); | 
|  | if (stateUNames == NULL) | 
|  | stateUNames = new Vector<char*>; | 
|  | stateUNames->store (value, strdup (stuname)); | 
|  | } | 
|  |  | 
|  | char * | 
|  | PropDescr::getStateName (int value) | 
|  | { | 
|  | if (stateNames && value >= 0 && value < stateNames->size ()) | 
|  | return stateNames->fetch (value); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | char * | 
|  | PropDescr::getStateUName (int value) | 
|  | { | 
|  | if (stateUNames && value >= 0 && value < stateUNames->size ()) | 
|  | return stateUNames->fetch (value); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *    class FieldDescr | 
|  | */ | 
|  |  | 
|  | FieldDescr::FieldDescr (int _propID, const char *_name) | 
|  | { | 
|  | propID = _propID; | 
|  | name = _name ? strdup (_name) : NULL; | 
|  | offset = 0; | 
|  | vtype = TYPE_NONE; | 
|  | format = NULL; | 
|  | } | 
|  |  | 
|  | FieldDescr::~FieldDescr () | 
|  | { | 
|  | free (name); | 
|  | free (format); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *    class PacketDescriptor | 
|  | */ | 
|  |  | 
|  | PacketDescriptor::PacketDescriptor (DataDescriptor *_ddscr) | 
|  | { | 
|  | ddscr = _ddscr; | 
|  | fields = new Vector<FieldDescr*>; | 
|  | } | 
|  |  | 
|  | PacketDescriptor::~PacketDescriptor () | 
|  | { | 
|  | fields->destroy (); | 
|  | delete fields; | 
|  | } | 
|  |  | 
|  | void | 
|  | PacketDescriptor::addField (FieldDescr *fldDscr) | 
|  | { | 
|  | if (fldDscr == NULL) | 
|  | return; | 
|  | fields->append (fldDscr); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *    class Data | 
|  | */ | 
|  |  | 
|  | /* Check compatibility between Datum and Data */ | 
|  | static void | 
|  | checkCompatibility (VType_type v1, VType_type v2) | 
|  | { | 
|  | switch (v1) | 
|  | { | 
|  | case TYPE_NONE: | 
|  | case TYPE_STRING: | 
|  | case TYPE_DOUBLE: | 
|  | case TYPE_OBJ: | 
|  | case TYPE_DATE: | 
|  | assert (v1 == v2); | 
|  | break; | 
|  | case TYPE_INT32: | 
|  | case TYPE_UINT32: | 
|  | assert (v2 == TYPE_INT32 || | 
|  | v2 == TYPE_UINT32); | 
|  | break; | 
|  | case TYPE_INT64: | 
|  | case TYPE_UINT64: | 
|  | assert (v2 == TYPE_INT64 || | 
|  | v2 == TYPE_UINT64); | 
|  | break; | 
|  | default: | 
|  | assert (0); | 
|  | } | 
|  | } | 
|  |  | 
|  | class DataINT32 : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataINT32 () | 
|  | { | 
|  | data = new Vector<int32_t>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataINT32 () | 
|  | { | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return TYPE_INT32; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long i) | 
|  | { | 
|  | return (int) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long i) | 
|  | { | 
|  | return (unsigned long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long i) | 
|  | { | 
|  | return (long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return dbe_sprintf (NTXT ("%d"), data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long i) | 
|  | { | 
|  | return (double) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->i); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long idx, uint64_t val) | 
|  | { | 
|  | data->store (idx, (int32_t) val); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long, void*) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long idx1, long idx2) | 
|  | { | 
|  | int32_t i1 = data->fetch (idx1); | 
|  | int32_t i2 = data->fetch (idx2); | 
|  | return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | int32_t i1 = data->fetch (idx); | 
|  | int32_t i2 = val->i; | 
|  | return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Vector<int32_t> *data; | 
|  | }; | 
|  |  | 
|  | class DataUINT32 : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataUINT32 () | 
|  | { | 
|  | data = new Vector<uint32_t>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataUINT32 () | 
|  | { | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return TYPE_UINT32; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long i) | 
|  | { | 
|  | return (int) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long i) | 
|  | { | 
|  | return (unsigned long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long i) | 
|  | { | 
|  | return (long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return dbe_sprintf (NTXT ("%u"), data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long i) | 
|  | { | 
|  | return (double) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->i); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long idx, uint64_t val) | 
|  | { | 
|  | data->store (idx, (uint32_t) val); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long, void*) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long idx1, long idx2) | 
|  | { | 
|  | uint32_t u1 = data->fetch (idx1); | 
|  | uint32_t u2 = data->fetch (idx2); | 
|  | return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | uint32_t u1 = data->fetch (idx); | 
|  | uint32_t u2 = (uint32_t) val->i; | 
|  | return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Vector<uint32_t> *data; | 
|  | }; | 
|  |  | 
|  | class DataINT64 : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataINT64 () | 
|  | { | 
|  | data = new Vector<int64_t>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataINT64 () | 
|  | { | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return TYPE_INT64; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long i) | 
|  | { | 
|  | return (int) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long i) | 
|  | { | 
|  | return (unsigned long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long i) | 
|  | { | 
|  | return (long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return dbe_sprintf (NTXT ("%lld"), (long long) data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long i) | 
|  | { | 
|  | return (double) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->ll); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long idx, uint64_t val) | 
|  | { | 
|  | data->store (idx, (int64_t) val); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long, void*) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long idx1, long idx2) | 
|  | { | 
|  | int64_t i1 = data->fetch (idx1); | 
|  | int64_t i2 = data->fetch (idx2); | 
|  | return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | int64_t i1 = data->fetch (idx); | 
|  | int64_t i2 = val->ll; | 
|  | return i1 < i2 ? -1 : i1 > i2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Vector<int64_t> *data; | 
|  | }; | 
|  |  | 
|  | class DataUINT64 : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataUINT64 () | 
|  | { | 
|  | data = new Vector<uint64_t>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataUINT64 () | 
|  | { | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return TYPE_UINT64; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long i) | 
|  | { | 
|  | return (int) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long i) | 
|  | { | 
|  | return (unsigned long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long i) | 
|  | { | 
|  | return (long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return dbe_sprintf (NTXT ("%llu"), (long long) data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long i) | 
|  | { | 
|  | return (double) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->ll); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long idx, uint64_t val) | 
|  | { | 
|  | data->store (idx, val); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long, void*) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long idx1, long idx2) | 
|  | { | 
|  | uint64_t u1 = data->fetch (idx1); | 
|  | uint64_t u2 = data->fetch (idx2); | 
|  | return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | uint64_t u1 = data->fetch (idx); | 
|  | uint64_t u2 = (uint64_t) val->ll; | 
|  | return u1 < u2 ? -1 : u1 > u2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Vector<uint64_t> *data; | 
|  | }; | 
|  |  | 
|  | class DataOBJECT : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataOBJECT () | 
|  | { | 
|  | dtype = TYPE_OBJ; | 
|  | data = new Vector<void*>; | 
|  | } | 
|  |  | 
|  | DataOBJECT (VType_type _dtype) | 
|  | { | 
|  | dtype = _dtype; | 
|  | data = new Vector<void*>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataOBJECT () | 
|  | { | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return dtype; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return 0LL; | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return 0LL; | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return dbe_sprintf (NTXT ("%lu"), (unsigned long) data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return 0.0; | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long i) | 
|  | { | 
|  | return data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->p); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long, uint64_t) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long idx, void *p) | 
|  | { | 
|  | data->store (idx, p); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long, long) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long, const Datum *) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | VType_type dtype; | 
|  | Vector<void*> *data; | 
|  | }; | 
|  |  | 
|  | class DataSTRING : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataSTRING () | 
|  | { | 
|  | data = new Vector<char*>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataSTRING () | 
|  | { | 
|  | data->destroy (); | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return TYPE_STRING; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long) | 
|  | { | 
|  | return 0LL; | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long) | 
|  | { | 
|  | return 0LL; | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return strdup (data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long) | 
|  | { | 
|  | return 0.0; | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long i) | 
|  | { | 
|  | return data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->l); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long, uint64_t) | 
|  | { | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long idx, void *p) | 
|  | { | 
|  | data->store (idx, (char*) p); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long, long) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long, const Datum *) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Vector<char*> *data; | 
|  | }; | 
|  |  | 
|  | class DataDOUBLE : public Data | 
|  | { | 
|  | public: | 
|  |  | 
|  | DataDOUBLE () | 
|  | { | 
|  | data = new Vector<double>; | 
|  | } | 
|  |  | 
|  | virtual | 
|  | ~DataDOUBLE () | 
|  | { | 
|  | delete data; | 
|  | } | 
|  |  | 
|  | virtual VType_type | 
|  | type () | 
|  | { | 
|  | return TYPE_DOUBLE; | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | reset () | 
|  | { | 
|  | data->reset (); | 
|  | } | 
|  |  | 
|  | virtual long | 
|  | getSize () | 
|  | { | 
|  | return data->size (); | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | fetchInt (long i) | 
|  | { | 
|  | return (int) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual unsigned long long | 
|  | fetchULong (long i) | 
|  | { | 
|  | return (unsigned long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual long long | 
|  | fetchLong (long i) | 
|  | { | 
|  | return (long long) data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual char * | 
|  | fetchString (long i) | 
|  | { | 
|  | return dbe_sprintf (NTXT ("%f"), data->fetch (i)); | 
|  | } | 
|  |  | 
|  | virtual double | 
|  | fetchDouble (long i) | 
|  | { | 
|  | return data->fetch (i); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | data->store (idx, val->d); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setValue (long idx, uint64_t val) | 
|  | { | 
|  | data->store (idx, (double) val); | 
|  | } | 
|  |  | 
|  | virtual void | 
|  | setObjValue (long, void*) | 
|  | { | 
|  | return; | 
|  | } | 
|  |  | 
|  | virtual void * | 
|  | fetchObject (long) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpValues (long idx1, long idx2) | 
|  | { | 
|  | double d1 = data->fetch (idx1); | 
|  | double d2 = data->fetch (idx2); | 
|  | return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | virtual int | 
|  | cmpDatumValue (long idx, const Datum *val) | 
|  | { | 
|  | double d1 = data->fetch (idx); | 
|  | double d2 = val->d; | 
|  | return d1 < d2 ? -1 : d1 > d2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Vector<double> *data; | 
|  | }; | 
|  |  | 
|  | Data * | 
|  | Data::newData (VType_type vtype) | 
|  | { | 
|  | switch (vtype) | 
|  | { | 
|  | case TYPE_INT32: | 
|  | return new DataINT32; | 
|  | case TYPE_UINT32: | 
|  | return new DataUINT32; | 
|  | case TYPE_INT64: | 
|  | return new DataINT64; | 
|  | case TYPE_UINT64: | 
|  | return new DataUINT64; | 
|  | case TYPE_OBJ: | 
|  | return new DataOBJECT; | 
|  | case TYPE_STRING: | 
|  | return new DataSTRING; | 
|  | case TYPE_DOUBLE: | 
|  | return new DataDOUBLE; | 
|  | default: | 
|  | return NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | *    class DataDescriptor | 
|  | */ | 
|  | DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname, | 
|  | int _flags) | 
|  | { | 
|  | isMaster = true; | 
|  | id = _id; | 
|  | name = _name ? strdup (_name) : strdup (NTXT ("")); | 
|  | uname = _uname ? strdup (_uname) : strdup (NTXT ("")); | 
|  | flags = _flags; | 
|  |  | 
|  | // master data, shared with reference copies: | 
|  | master_size = 0; | 
|  | master_resolveFrameInfoDone = false; | 
|  | props = new Vector<PropDescr*>; | 
|  | data = new Vector<Data*>; | 
|  | setsTBR = new Vector<Vector<long long>*>; | 
|  |  | 
|  | // master references point to self: | 
|  | ref_size = &master_size; | 
|  | ref_resolveFrameInfoDone = &master_resolveFrameInfoDone; | 
|  | } | 
|  |  | 
|  | DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname, | 
|  | DataDescriptor* dDscr) | 
|  | { | 
|  | isMaster = false; | 
|  | id = _id; | 
|  | name = _name ? strdup (_name) : strdup (NTXT ("")); | 
|  | uname = _uname ? strdup (_uname) : strdup (NTXT ("")); | 
|  | flags = dDscr->flags; | 
|  |  | 
|  | // references point to master DataDescriptor | 
|  | ref_size = &dDscr->master_size; | 
|  | ref_resolveFrameInfoDone = &dDscr->master_resolveFrameInfoDone; | 
|  | props = dDscr->props; | 
|  | data = dDscr->data; | 
|  | setsTBR = dDscr->setsTBR; | 
|  |  | 
|  | // data that should never be accessed in reference copy | 
|  | master_size = -1; | 
|  | master_resolveFrameInfoDone = false; | 
|  | } | 
|  |  | 
|  | DataDescriptor::~DataDescriptor () | 
|  | { | 
|  | free (name); | 
|  | free (uname); | 
|  | if (!isMaster) | 
|  | return; | 
|  | props->destroy (); | 
|  | delete props; | 
|  | data->destroy (); | 
|  | delete data; | 
|  | setsTBR->destroy (); | 
|  | delete setsTBR; | 
|  | } | 
|  |  | 
|  | void | 
|  | DataDescriptor::reset () | 
|  | { | 
|  | if (!isMaster) | 
|  | return; | 
|  | for (int i = 0; i < data->size (); i++) | 
|  | { | 
|  | Data *d = data->fetch (i); | 
|  | if (d != NULL) | 
|  | d->reset (); | 
|  | Vector<long long> *set = setsTBR->fetch (i); | 
|  | if (set != NULL) | 
|  | set->reset (); | 
|  | } | 
|  | master_size = 0; | 
|  | } | 
|  |  | 
|  | PropDescr * | 
|  | DataDescriptor::getProp (int prop_id) | 
|  | { | 
|  | for (int i = 0; i < props->size (); i++) | 
|  | { | 
|  | PropDescr *propDscr = props->fetch (i); | 
|  | if (propDscr->propID == prop_id) | 
|  | return propDscr; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | Data * | 
|  | DataDescriptor::getData (int prop_id) | 
|  | { | 
|  | if (prop_id < 0 || prop_id >= data->size ()) | 
|  | return NULL; | 
|  | return data->fetch (prop_id); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataDescriptor::addProperty (PropDescr *propDscr) | 
|  | { | 
|  | if (propDscr == NULL) | 
|  | return; | 
|  | if (propDscr->propID < 0) | 
|  | return; | 
|  | PropDescr *oldProp = getProp (propDscr->propID); | 
|  | if (oldProp != NULL) | 
|  | { | 
|  | checkCompatibility (propDscr->vtype, oldProp->vtype); //YXXX depends on experiment correctness | 
|  | delete propDscr; | 
|  | return; | 
|  | } | 
|  | props->append (propDscr); | 
|  | data->store (propDscr->propID, Data::newData (propDscr->vtype)); | 
|  | setsTBR->store (propDscr->propID, NULL); | 
|  | } | 
|  |  | 
|  | long | 
|  | DataDescriptor::addRecord () | 
|  | { | 
|  | if (!isMaster) | 
|  | return -1; | 
|  | return master_size++; | 
|  | } | 
|  |  | 
|  | static void | 
|  | checkEntity (Vector<long long> *set, long long val) | 
|  | { | 
|  | // Binary search | 
|  | int lo = 0; | 
|  | int hi = set->size () - 1; | 
|  | while (lo <= hi) | 
|  | { | 
|  | int md = (lo + hi) / 2; | 
|  | long long ent = set->fetch (md); | 
|  | if (ent < val) | 
|  | lo = md + 1; | 
|  | else if (ent > val) | 
|  | hi = md - 1; | 
|  | else | 
|  | return; | 
|  | } | 
|  | set->insert (lo, val); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataDescriptor::setDatumValue (int prop_id, long idx, const Datum *val) | 
|  | { | 
|  | if (idx >= *ref_size) | 
|  | return; | 
|  | Data *d = getData (prop_id); | 
|  | if (d != NULL) | 
|  | { | 
|  | VType_type datum_type = val->type; | 
|  | VType_type data_type = d->type (); | 
|  | checkCompatibility (datum_type, data_type); | 
|  | d->setDatumValue (idx, val); | 
|  | Vector<long long> *set = setsTBR->fetch (prop_id); | 
|  | if (set != NULL)// Sets are maintained | 
|  | checkEntity (set, d->fetchLong (idx)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | DataDescriptor::setValue (int prop_id, long idx, uint64_t val) | 
|  | { | 
|  | if (idx >= *ref_size) | 
|  | return; | 
|  | Data *d = getData (prop_id); | 
|  | if (d != NULL) | 
|  | { | 
|  | d->setValue (idx, val); | 
|  | Vector<long long> *set = setsTBR->fetch (prop_id); | 
|  | if (set != NULL)// Sets are maintained | 
|  | checkEntity (set, d->fetchLong (idx)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | DataDescriptor::setObjValue (int prop_id, long idx, void *val) | 
|  | { | 
|  | if (idx >= *ref_size) | 
|  | return; | 
|  | Data *d = getData (prop_id); | 
|  | if (d != NULL) | 
|  | d->setObjValue (idx, val); | 
|  | } | 
|  |  | 
|  | DataView * | 
|  | DataDescriptor::createView () | 
|  | { | 
|  | return new DataView (this); | 
|  | } | 
|  |  | 
|  | DataView * | 
|  | DataDescriptor::createImmutableView () | 
|  | { | 
|  | return new DataView (this, DataView::DV_IMMUTABLE); | 
|  | } | 
|  |  | 
|  | DataView * | 
|  | DataDescriptor::createExtManagedView () | 
|  | { | 
|  | return new DataView (this, DataView::DV_EXT_MANAGED); | 
|  | } | 
|  |  | 
|  | int | 
|  | DataDescriptor::getIntValue (int prop_id, long idx) | 
|  | { | 
|  | Data *d = getData (prop_id); | 
|  | if (d == NULL || idx >= d->getSize ()) | 
|  | return 0; | 
|  | return d->fetchInt (idx); | 
|  | } | 
|  |  | 
|  | unsigned long long | 
|  | DataDescriptor::getULongValue (int prop_id, long idx) | 
|  | { | 
|  | Data *d = getData (prop_id); | 
|  | if (d == NULL || idx >= d->getSize ()) | 
|  | return 0L; | 
|  | return d->fetchULong (idx); | 
|  | } | 
|  |  | 
|  | long long | 
|  | DataDescriptor::getLongValue (int prop_id, long idx) | 
|  | { | 
|  | Data *d = getData (prop_id); | 
|  | if (d == NULL || idx >= d->getSize ()) | 
|  | return 0L; | 
|  | return d->fetchLong (idx); | 
|  | } | 
|  |  | 
|  | void * | 
|  | DataDescriptor::getObjValue (int prop_id, long idx) | 
|  | { | 
|  | Data *d = getData (prop_id); | 
|  | if (d == NULL || idx >= d->getSize ()) | 
|  | return NULL; | 
|  | return d->fetchObject (idx); | 
|  | } | 
|  |  | 
|  | static int | 
|  | pcmp (const void *p1, const void *p2, const void *arg) | 
|  | { | 
|  | long idx1 = *(long*) p1; // index1 into Data | 
|  | long idx2 = *(long*) p2; // index2 into Data | 
|  | for (Data **dsorted = (Data**) arg; *dsorted != DATA_SORT_EOL; dsorted++) | 
|  | { | 
|  | Data *data = *dsorted; | 
|  | if (data == NULL)// sort property not in this data, skip this criteria | 
|  | continue; | 
|  | int res = data->cmpValues (idx1, idx2); | 
|  | if (res) | 
|  | return res; | 
|  | } | 
|  | // Provide stable sort | 
|  | return idx1 < idx2 ? -1 : idx1 > idx2 ? 1 : 0; | 
|  | } | 
|  |  | 
|  | Vector<long long> * | 
|  | DataDescriptor::getSet (int prop_id) | 
|  | { | 
|  | if (prop_id < 0 || prop_id >= setsTBR->size ()) | 
|  | return NULL; | 
|  | Vector<long long> *set = setsTBR->fetch (prop_id); | 
|  | if (set != NULL) | 
|  | return set; | 
|  |  | 
|  | Data *d = getData (prop_id); | 
|  | if (d == NULL) | 
|  | return NULL; | 
|  | set = new Vector<long long>; | 
|  | for (long i = 0; i<*ref_size; ++i) | 
|  | checkEntity (set, d->fetchLong (i)); | 
|  | setsTBR->store (prop_id, set); | 
|  |  | 
|  | return set; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *    class DataView | 
|  | */ | 
|  | DataView::DataView (DataDescriptor *_ddscr) | 
|  | { | 
|  | init (_ddscr, DV_NORMAL); | 
|  | } | 
|  |  | 
|  | DataView::DataView (DataDescriptor *_ddscr, DataViewType _type) | 
|  | { | 
|  | init (_ddscr, _type); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::init (DataDescriptor *_ddscr, DataViewType _type) | 
|  | { | 
|  | ddscr = _ddscr; | 
|  | type = _type; | 
|  | switch (type) | 
|  | { | 
|  | case DV_IMMUTABLE: | 
|  | ddsize = ddscr->getSize (); | 
|  | index = NULL; | 
|  | break; | 
|  | case DV_NORMAL: | 
|  | case DV_EXT_MANAGED: | 
|  | ddsize = 0; | 
|  | index = new Vector<long>; | 
|  | break; | 
|  | } | 
|  | for (int ii = 0; ii < (MAX_SORT_DIMENSIONS + 1); ii++) | 
|  | sortedBy[ii] = DATA_SORT_EOL; | 
|  | filter = NULL; | 
|  | } | 
|  |  | 
|  | DataView::~DataView () | 
|  | { | 
|  | delete filter; | 
|  | delete index; | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::appendDataDescriptorId (long pkt_id /* ddscr index */) | 
|  | { | 
|  | if (type != DV_EXT_MANAGED) | 
|  | return; // updates allowed only on externally managed DataViews | 
|  | long curr_ddsize = ddscr->getSize (); | 
|  | if (pkt_id < 0 || pkt_id >= curr_ddsize) | 
|  | return; // error! | 
|  | index->append (pkt_id); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::setDataDescriptorValue (int prop_id, long pkt_id, uint64_t val) | 
|  | { | 
|  | ddscr->setValue (prop_id, pkt_id, val); | 
|  | } | 
|  |  | 
|  | long long | 
|  | DataView::getDataDescriptorValue (int prop_id, long pkt_id) | 
|  | { | 
|  | return ddscr->getLongValue (prop_id, pkt_id); | 
|  | } | 
|  |  | 
|  | Vector<PropDescr*>* | 
|  | DataView::getProps () | 
|  | { | 
|  | return ddscr->getProps (); | 
|  | }; | 
|  |  | 
|  | PropDescr* | 
|  | DataView::getProp (int prop_id) | 
|  | { | 
|  | return ddscr->getProp (prop_id); | 
|  | }; | 
|  |  | 
|  | void | 
|  | DataView::filter_in_chunks (fltr_dbe_ctx *dctx) | 
|  | { | 
|  | Expression::Context *e_ctx = new Expression::Context (dctx->fltr->ctx->dbev, dctx->fltr->ctx->exp); | 
|  | Expression *n_expr = dctx->fltr->expr->copy (); | 
|  | bool noParFilter = dctx->fltr->noParFilter; | 
|  | FilterExp *nFilter = new FilterExp (n_expr, e_ctx, noParFilter); | 
|  | long iter = dctx->begin; | 
|  | long end = dctx->end; | 
|  | long orig_ddsize = dctx->orig_ddsize; | 
|  | while (iter < end) | 
|  | { | 
|  | nFilter->put (dctx->tmpView, iter); | 
|  | if (nFilter->passes ()) | 
|  | dctx->idxArr[iter - orig_ddsize] = 1; | 
|  | iter += 1; | 
|  | } | 
|  | delete nFilter; | 
|  | } | 
|  |  | 
|  | bool | 
|  | DataView::checkUpdate () | 
|  | { | 
|  | long newSize = ddscr->getSize (); | 
|  | if (ddsize == newSize) | 
|  | return false; | 
|  | if (index == NULL) | 
|  | return false; | 
|  | if (type == DV_EXT_MANAGED) | 
|  | return false; | 
|  | bool updated = false; | 
|  | if (filter) | 
|  | { | 
|  | DataView *tmpView = ddscr->createImmutableView (); | 
|  | assert (tmpView->getSize () == newSize); | 
|  | while (ddsize < newSize) | 
|  | { | 
|  | filter->put (tmpView, ddsize); | 
|  | if (filter->passes ()) | 
|  | index->append (ddsize); | 
|  | ddsize += 1; | 
|  | } | 
|  | delete tmpView; | 
|  | return updated; | 
|  | } | 
|  | while (ddsize < newSize) | 
|  | { | 
|  | index->append (ddsize); | 
|  | updated = true; | 
|  | ddsize += 1; | 
|  | } | 
|  | return updated; | 
|  | } | 
|  |  | 
|  | long | 
|  | DataView::getSize () | 
|  | { | 
|  | if (checkUpdate () && sortedBy[0] != DATA_SORT_EOL) | 
|  | // note: after new filter is set, getSize() incurs cost of | 
|  | // sorting even if caller isn't interested in sort | 
|  | index->sort ((CompareFunc) pcmp, sortedBy); | 
|  |  | 
|  | if (index == NULL) | 
|  | return ddscr->getSize (); | 
|  | return index->size (); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::setDatumValue (int prop_id, long idx, const Datum *val) | 
|  | { | 
|  | ddscr->setDatumValue (prop_id, getIdByIdx (idx), val); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::setValue (int prop_id, long idx, uint64_t val) | 
|  | { | 
|  | ddscr->setValue (prop_id, getIdByIdx (idx), val); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::setObjValue (int prop_id, long idx, void *val) | 
|  | { | 
|  | ddscr->setObjValue (prop_id, getIdByIdx (idx), val); | 
|  | } | 
|  |  | 
|  | int | 
|  | DataView::getIntValue (int prop_id, long idx) | 
|  | { | 
|  | return ddscr->getIntValue (prop_id, getIdByIdx (idx)); | 
|  | } | 
|  |  | 
|  | unsigned long long | 
|  | DataView::getULongValue (int prop_id, long idx) | 
|  | { | 
|  | return ddscr->getULongValue (prop_id, getIdByIdx (idx)); | 
|  | } | 
|  |  | 
|  | long long | 
|  | DataView::getLongValue (int prop_id, long idx) | 
|  | { | 
|  | return ddscr->getLongValue (prop_id, getIdByIdx (idx)); | 
|  | } | 
|  |  | 
|  | void * | 
|  | DataView::getObjValue (int prop_id, long idx) | 
|  | { | 
|  | return ddscr->getObjValue (prop_id, getIdByIdx (idx)); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::sort (const int props[], int prop_count) | 
|  | { | 
|  | if (index == NULL) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  | assert (prop_count >= 0 && prop_count < MAX_SORT_DIMENSIONS); | 
|  | bool sort_changed = false; // see if sort has changed... | 
|  | for (int ii = 0; ii <= prop_count; ii++) | 
|  | { // sortedBy size is prop_count+1 | 
|  | Data *data; | 
|  | if (ii == prop_count) | 
|  | data = DATA_SORT_EOL; // special end of array marker | 
|  | else | 
|  | data = ddscr->getData (props[ii]); | 
|  | if (sortedBy[ii] != data) | 
|  | { | 
|  | sortedBy[ii] = data; | 
|  | sort_changed = true; | 
|  | } | 
|  | } | 
|  | if (!checkUpdate () && !sort_changed) | 
|  | return; | 
|  | index->sort ((CompareFunc) pcmp, sortedBy); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::sort (int prop0) | 
|  | { | 
|  | sort (&prop0, 1); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::sort (int prop0, int prop1) | 
|  | { | 
|  | int props[2] = {prop0, prop1}; | 
|  | sort (props, 2); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::sort (int prop0, int prop1, int prop2) | 
|  | { | 
|  | int props[3] = {prop0, prop1, prop2}; | 
|  | sort (props, 3); | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::setFilter (FilterExp *f) | 
|  | { | 
|  | if (index == NULL) | 
|  | { | 
|  | assert (ASSERT_SKIP); | 
|  | return; | 
|  | } | 
|  | delete filter; | 
|  | filter = f; | 
|  | index->reset (); | 
|  | ddsize = 0; | 
|  | checkUpdate (); | 
|  | } | 
|  |  | 
|  | long | 
|  | DataView::getIdByIdx (long idx) | 
|  | { | 
|  | if (index == NULL) | 
|  | return idx; | 
|  | return index->fetch (idx); | 
|  | } | 
|  |  | 
|  | static int | 
|  | tvalcmp (long data_id, const Datum valColumns[], Data *sortedBy[]) | 
|  | { | 
|  | for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++) | 
|  | { | 
|  | if (sortedBy[ii] == DATA_SORT_EOL) | 
|  | break; | 
|  | Data *d = sortedBy[ii]; | 
|  | if (d == NULL)// property doesn't exist in data; compare always matches | 
|  | continue; | 
|  | const Datum *tvalue = &valColumns[ii]; | 
|  | int res = d->cmpDatumValue (data_id, tvalue); | 
|  | if (res) | 
|  | return res; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void | 
|  | checkSortTypes (const Datum valColumns[], Data *sortedBy[]) | 
|  | { | 
|  | #ifndef NDEBUG | 
|  | for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++) | 
|  | { | 
|  | if (sortedBy[ii] == DATA_SORT_EOL) | 
|  | break; | 
|  | Data *d = sortedBy[ii]; | 
|  | if (d == NULL)// property doesn't exist in data; compare always matches | 
|  | continue; | 
|  | VType_type datum_type = valColumns[ii].type; | 
|  | VType_type data_type = d->type (); | 
|  | checkCompatibility (datum_type, data_type); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | bool | 
|  | DataView::idxRootDimensionsMatch (long idx, const Datum valColumns[]) | 
|  | { | 
|  | // compares idx vs. valColumns[] - If all dimensions match | 
|  | // (except sort leaf), then the leaf value is valid => return true. | 
|  | // Otherwise, return false. | 
|  | checkSortTypes (valColumns, sortedBy); | 
|  | if (idx < 0 || idx >= index->size ()) // fell off end of array | 
|  | return false; | 
|  | long data_id = index->fetch (idx); | 
|  |  | 
|  | // we will check all dimensions for a match except the "leaf" dimension | 
|  | for (int ii = 0; ii < (MAX_SORT_DIMENSIONS - 1); ii++) | 
|  | { | 
|  | if (sortedBy[ii + 1] == DATA_SORT_EOL) | 
|  | break; // we are at leaf dimension, don't care about it's value | 
|  | if (sortedBy[ii] == DATA_SORT_EOL) | 
|  | break; // end of list | 
|  | Data *d = sortedBy[ii]; | 
|  | if (d == NULL) // property doesn't exist in data; compare always matches | 
|  | continue; | 
|  | const Datum *tvalue = &valColumns[ii]; | 
|  | int res = d->cmpDatumValue (data_id, tvalue); | 
|  | if (res) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | long | 
|  | DataView::getIdxByVals (const Datum valColumns[], Relation rel) | 
|  | { | 
|  | // checks sortedBy[] columns for match; relation only used on last column | 
|  | return getIdxByVals (valColumns, rel, -1, -1); | 
|  | } | 
|  |  | 
|  | long | 
|  | DataView::getIdxByVals (const Datum valColumns[], Relation rel, | 
|  | long minIdx, long maxIdx) | 
|  | { | 
|  | // checks sortedBy[] columns for match; relation only used on last column | 
|  | checkSortTypes (valColumns, sortedBy); | 
|  | if (index == NULL || sortedBy[0] == DATA_SORT_EOL) | 
|  | return -1; | 
|  |  | 
|  | long lo; | 
|  | if (minIdx < 0) | 
|  | lo = 0; | 
|  | else | 
|  | lo = minIdx; | 
|  |  | 
|  | long hi; | 
|  | if (maxIdx < 0 || maxIdx >= index->size ()) | 
|  | hi = index->size () - 1; | 
|  | else | 
|  | hi = maxIdx; | 
|  |  | 
|  | long md = -1; | 
|  | while (lo <= hi) | 
|  | { | 
|  | md = (lo + hi) / 2; | 
|  | int cmp = tvalcmp (index->fetch (md), valColumns, sortedBy); | 
|  | if (cmp < 0) | 
|  | { | 
|  | lo = md + 1; | 
|  | continue; | 
|  | } | 
|  | else if (cmp > 0) | 
|  | { | 
|  | hi = md - 1; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // cmp == 0, we have an exact match | 
|  | switch (rel) | 
|  | { | 
|  | case REL_LT: | 
|  | hi = md - 1; // continue searching | 
|  | break; | 
|  | case REL_GT: | 
|  | lo = md + 1; // continue searching | 
|  | break; | 
|  | case REL_LTEQ: | 
|  | case REL_GTEQ: | 
|  | case REL_EQ: | 
|  | // note: "md" may not be deterministic if multiple matches exist | 
|  | return md; // a match => done. | 
|  | } | 
|  | } | 
|  |  | 
|  | // no exact match found | 
|  | switch (rel) | 
|  | { | 
|  | case REL_LT: | 
|  | case REL_LTEQ: | 
|  | md = hi; | 
|  | break; | 
|  | case REL_GT: | 
|  | case REL_GTEQ: | 
|  | md = lo; | 
|  | break; | 
|  | case REL_EQ: | 
|  | return -1; | 
|  | } | 
|  | if (idxRootDimensionsMatch (md, valColumns)) | 
|  | return md; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | void | 
|  | DataView::removeDbeViewIdx (long idx) | 
|  | { | 
|  | index->remove (idx); | 
|  | } | 
|  |  |