Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ae110ed
Add a template typed base PythonObject which provides the interface f…
Sep 12, 2019
da6ffd6
Add AddToDict method to the PythonObject interface.
Sep 12, 2019
c8cbf7b
Initial implementation of a PythonObject derived class which supports…
Sep 13, 2019
e4445ae
Select the type of PythonObject to create based on the column value c…
Sep 13, 2019
fda8a6c
Update bridge setter methods to take in both row and column rather th…
Sep 13, 2019
1b9ba54
Enable variable length columns for non-csr output data.
Sep 13, 2019
ef64291
Add column full of NaNs if no output value was ever specified.
Sep 13, 2019
9f20a35
Fix compile issues with the last checkin.
Sep 13, 2019
3e61f30
Merge branch 'master' into variable-length-vector
ganik Sep 17, 2019
5defe1f
Add proper PythonObjectVariable deleter.
Sep 17, 2019
41c98e4
Initial skeleton code for testing variable length column value support.
Sep 17, 2019
d303d1e
Merge remote-tracking branch 'origin/variable-length-vector' into var…
Sep 17, 2019
63bd45e
Add support for specifying vector lengths to VariableColumnTransform.
Sep 19, 2019
426c060
Fix exception message in VariableColumnTransform.
Sep 19, 2019
d52b60f
Add initial tests for the variable length output conversion.
Sep 19, 2019
13fa748
Force re-run of ci tests since linux build crashed on previous run.
Sep 19, 2019
bc224b9
Zero pad column names when converting variable length vector columns.
Sep 20, 2019
042a4ac
Merge remote-tracking branch 'upstream/master' into variable-length-v…
Sep 20, 2019
6e00598
Use the new entrypoints file in DotNetBridge for the VariableColumnTr…
Sep 20, 2019
3a1caf8
Merge branch 'master' into variable-length-vector
Sep 23, 2019
eb06ae3
Add more detailed comments regarding why integers are converted to fl…
Sep 25, 2019
3f0cde9
Merge branch 'master' into variable-length-vector
Sep 25, 2019
39bf5c0
Rename the PythonObject* classes to PyColumn* in NativeBridge.
Sep 25, 2019
c9b2884
Clean up indentation and comments.
Sep 25, 2019
4b129d4
Refactor PyColumnVariable to support different behaviors for other ty…
Sep 26, 2019
15a474d
Add string column type support.
Sep 26, 2019
823ba3e
Merge branch 'master' into variable-length-vector
Sep 27, 2019
95e28f3
Fix int32 to float32 conversion losses precision.
Sep 27, 2019
e97079e
Clean up pointer usage in PyColumnVariable.
Sep 27, 2019
20dda09
Remove numCols from creation of PyColumn based classes.
Sep 27, 2019
0b3c993
Remove unnecessary assembly attribute.
Sep 27, 2019
1facdf5
Set initial capacity of valueCounts list in NativeDataInterop.
Sep 27, 2019
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
18 changes: 13 additions & 5 deletions src/DotNetBridge/NativeDataInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ private struct DataViewBlock
// key types. Zero means unbounded, -1 means not a key type.
[FieldOffset(0x20)]
public int* keyCards;

// The number of values in each row of a column.
// A value count of 0 means that each row of the column
// is variable length.
[FieldOffset(0x28)]
public byte* valueCounts;
}

private struct ColumnMetadataInfo
Expand Down Expand Up @@ -113,6 +119,7 @@ private static unsafe void SendViewToNativeAsDataFrame(IChannel ch, EnvironmentB
var keyCardList = new List<int>();
var nameUtf8Bytes = new List<Byte>();
var nameIndices = new List<int>();
var valueCounts = new List<byte>();

var expandCols = new HashSet<int>();
var allNames = new HashSet<string>();
Expand All @@ -129,11 +136,7 @@ private static unsafe void SendViewToNativeAsDataFrame(IChannel ch, EnvironmentB
var kind = itemType.GetRawKind();
int keyCard;

if (fullType.GetValueCount() == 0)
{
throw ch.ExceptNotSupp("Column has variable length vector: " +
name + ". Not supported in python. Drop column before sending to Python");
}
byte valueCount = (fullType.GetValueCount() == 0) ? (byte)0 : (byte)1;

if (itemType is KeyDataViewType)
{
Expand Down Expand Up @@ -232,22 +235,26 @@ private static unsafe void SendViewToNativeAsDataFrame(IChannel ch, EnvironmentB
{
kindList.Add(kind);
keyCardList.Add(keyCard);
valueCounts.Add(valueCount);
}
}

ch.Assert(allNames.Count == kindList.Count);
ch.Assert(allNames.Count == keyCardList.Count);
ch.Assert(allNames.Count == nameIndices.Count);
ch.Assert(allNames.Count == valueCounts.Count);

var kinds = kindList.ToArray();
var keyCards = keyCardList.ToArray();
var nameBytes = nameUtf8Bytes.ToArray();
var names = new byte*[allNames.Count];
var valueCountsBytes = valueCounts.ToArray();

fixed (InternalDataKind* prgkind = kinds)
fixed (byte* prgbNames = nameBytes)
fixed (byte** prgname = names)
fixed (int* prgkeyCard = keyCards)
fixed (byte* prgbValueCount = valueCountsBytes)
{
for (int iid = 0; iid < names.Length; iid++)
names[iid] = prgbNames + nameIndices[iid];
Expand All @@ -258,6 +265,7 @@ private static unsafe void SendViewToNativeAsDataFrame(IChannel ch, EnvironmentB
block.names = (sbyte**)prgname;
block.kinds = prgkind;
block.keyCards = prgkeyCard;
block.valueCounts = prgbValueCount;

dataSink(penv, &block, out var setters, out var keyValueSetter);

Expand Down
4 changes: 4 additions & 0 deletions src/NativeBridge/DataViewInterop.h
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,10 @@ struct DataViewBlock
// Column key type cardinalities. Only contains the values for the columns that have
// key names.
const int *keyCards;
// The number of values in each row of a column.
// A value count of 0 means that each row of the column
// is variable length.
const BYTE *valueCounts;
};

enum ML_PY_TYPE_MAP_ENUM {
Expand Down
110 changes: 24 additions & 86 deletions src/NativeBridge/ManagedInterop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,16 @@
#include "DataViewInterop.h"
#include "ManagedInterop.h"

inline void destroyManagerCObject(PyObject* obj) {
auto* b = static_cast<PythonObjectBase*>(PyCapsule_GetPointer(obj, NULL));
if (b) { delete b; }
}

#define SetDict2(cpptype, nptype); \
{\
PythonObject<cpptype>* col = dynamic_cast<PythonObject<cpptype>*>(column);\
auto shrd = col->GetData();\
auto* data = shrd->data();\
bp::handle<> h(::PyCapsule_New((void*)column, NULL, (PyCapsule_Destructor)&destroyManagerCObject));\
dict[_names[i]] = np::from_data(\
data,\
np::dtype::get_builtin<nptype>(),\
bp::make_tuple(shrd->size()),\
bp::make_tuple(sizeof(nptype)), bp::object(h));\
}

#define SetDict1(type) SetDict2(type, type)

#define SetDictAndKeys(type, i); \
{\
PythonObject<type>* col = dynamic_cast<PythonObject<type>*>(column);\
auto shrd = col->GetData();\
auto* data = shrd->data();\
bp::handle<> h(::PyCapsule_New((void*)column, NULL, (PyCapsule_Destructor)&destroyManagerCObject));\
np::ndarray npdata = np::from_data(\
data,\
np::dtype::get_builtin<type>(),\
bp::make_tuple(shrd->size()),\
bp::make_tuple(sizeof(float)), bp::object(h));\
if (keyNames == nullptr)\
{\
dict[_names[i]] = npdata;\
}\
else\
{\
dict[_names[i]] = bp::dict();\
dict[_names[i]]["..Data"] = npdata;\
auto shrd = keyNames->GetData();\
bp::list list;\
for (int j = 0; j < shrd->size(); j++)\
{\
bp::object obj;\
const std::string& value = shrd->at(j);\
if (!value.empty())\
{\
obj = bp::object(value);\
}\
list.append(obj);\
}\
dict[_names[i]]["..KeyValues"] = list;\
}\
}\
#define AddToDict(type); \
{\
PythonObject<type>* col = dynamic_cast<PythonObject<type>*>(column);\
col->AddToDict(dict, _names[i], keyNames);\
}\

#define STATIC


EnvironmentBlock::~EnvironmentBlock()
{
// Everything (except data buffers) that we might have exposed to managed code,
Expand Down Expand Up @@ -115,7 +68,7 @@ void EnvironmentBlock::DataSinkCore(const DataViewBlock * pdata)
for (int i = 0; i < pdata->ccol; i++)
{
BYTE kind = pdata->kinds[i];
_columns.push_back(PythonObjectBase::CreateObject(kind, pdata->crow, 1));
_columns.push_back(PythonObjectBase::CreateObject(kind, pdata->crow, pdata->valueCounts[i]));

switch (kind)
{
Expand Down Expand Up @@ -164,7 +117,7 @@ void EnvironmentBlock::DataSinkCore(const DataViewBlock * pdata)

if (pdata->keyCards && (pdata->keyCards[i] >= 0))
{
_vKeyValues.push_back(new PythonObject<std::string>(TX, pdata->keyCards[i], 1));
_vKeyValues.push_back(new PythonObjectSingle<std::string>(TX, pdata->keyCards[i], 1));
_columnToKeyMap.push_back(numKeys++);
}
else
Expand Down Expand Up @@ -238,15 +191,15 @@ bp::dict EnvironmentBlock::GetData()
for (size_t i = 0; i < _names.size(); i++)
{
PythonObjectBase* column = _columns[i];
PythonObject<std::string>* keyNames = nullptr;
const std::vector<std::string>* keyNames = nullptr;
if (_columnToKeyMap[i] >= 0)
keyNames = _vKeyValues[_columnToKeyMap[i]];
keyNames = _vKeyValues[_columnToKeyMap[i]]->GetData();

signed char kind = column->GetKind();
switch (kind) {
case -1:
{
PythonObject<signed char>* col = dynamic_cast<PythonObject<signed char>*>(column);
PythonObjectSingle<signed char>* col = dynamic_cast<PythonObjectSingle<signed char>*>(column);
auto shrd = col->GetData();
bp::list list;
for (size_t i = 0; i < shrd->size(); i++)
Expand All @@ -266,57 +219,42 @@ bp::dict EnvironmentBlock::GetData()
}
break;
case BL:
SetDict2(signed char, bool);
AddToDict(signed char);
break;
case I1:
SetDictAndKeys(signed char, i);
AddToDict(signed char);
break;
case I2:
SetDictAndKeys(signed short, i);
AddToDict(signed short);
break;
case I4:
SetDictAndKeys(signed int, i);
AddToDict(signed int);
break;
case I8:
SetDict1(CxInt64);
AddToDict(CxInt64);
break;
case U1:
SetDict1(unsigned char);
AddToDict(unsigned char);
break;
case U2:
SetDict1(unsigned short);
AddToDict(unsigned short);
break;
case U4:
SetDict1(unsigned int);
AddToDict(unsigned int);
break;
case U8:
SetDict1(CxUInt64);
AddToDict(CxUInt64);
break;
case R4:
SetDict1(float);
AddToDict(float);
break;
case R8:
SetDict1(double);
AddToDict(double);
break;
case TX:
{
PythonObject<string>* col = dynamic_cast<PythonObject<string>*>(column);
auto shrd = col->GetData();
bp::list list;
for (size_t i = 0; i < shrd->size(); i++)
{
bp::object obj;
const std::string& value = shrd->at(i);
if (!value.empty())
{
obj = bp::object(value);
}
list.append(obj);
}
dict[_names[i]] = list;
AddToDict(std::string);
delete column;
}
break;
break;
case TS:
case DT:
case DZ:
Expand Down
2 changes: 1 addition & 1 deletion src/NativeBridge/ManagedInterop.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class CLASS_ALIGN EnvironmentBlock
// there are no key names.
std::vector<CxInt64> _columnToKeyMap;

std::vector<PythonObject<std::string>*> _vKeyValues;
std::vector<PythonObjectSingle<std::string>*> _vKeyValues;

static MANAGED_CALLBACK(void) SetR4(EnvironmentBlock *env, int col, long index, float value)
{
Expand Down
Loading