Vuo  2.3.2
VuoTable.cc
Go to the documentation of this file.
1 
10 #include <sstream>
11 #include <vector>
12 using namespace std;
13 
14 #include "type.h"
15 
16 extern "C"
17 {
18 #include "VuoTable.h"
19 #include "VuoTime.h"
20 
21 #include <csv.h>
22 
24 #ifdef VUO_COMPILER
26  "title" : "Table",
27  "description" : "Information structured in rows and columns.",
28  "keywords" : [ ],
29  "version" : "1.0.0",
30  "dependencies" : [
31  "VuoList_VuoTable",
32  "VuoTableFormat",
33  "VuoTextSort",
34  "VuoSortOrder",
35  "VuoText",
36  "VuoList_VuoText",
37  "VuoTime",
38  "csv"
39  ]
40  });
41 #endif
43 }
44 
48 static void deleteData(void *data)
49 {
50  delete (vector< vector<VuoText> > *)data;
51 }
52 
53 
58 {
59  json_object *o;
60  if (json_object_object_get_ex(js, "pointer", &o))
61  {
62  VuoTable table = { NULL, 0, 0 };
63 
64  table.data = (void *)json_object_get_int64(o);
65  if (! table.data)
66  {
67  table.data = new vector< vector<VuoText> >;
68  VuoRegister(table.data, deleteData);
69  }
70 
71  if (json_object_object_get_ex(js, "rowCount", &o))
72  table.rowCount = (size_t)json_object_get_int64(o);
73 
74  if (json_object_object_get_ex(js, "columnCount", &o))
75  table.columnCount = (size_t)json_object_get_int64(o);
76 
77  return table;
78  }
79  else if (json_object_object_get_ex(js, "csv", &o))
80  {
81  const char *tableAsCsv = json_object_get_string(o);
82 
83  return VuoTable_makeFromText(tableAsCsv, VuoTableFormat_Csv);
84  }
85 
86  return VuoTable_makeEmpty();
87 }
88 
92 struct json_object * VuoTable_getJson(const VuoTable value)
93 {
94  json_object *js = json_object_new_object();
95 
96  json_object_object_add(js, "pointer", json_object_new_int64((int64_t)value.data));
97  json_object_object_add(js, "rowCount", json_object_new_int64((int64_t)value.rowCount));
98  json_object_object_add(js, "columnCount", json_object_new_int64((int64_t)value.columnCount));
99 
100  return js;
101 }
102 
107 {
108  json_object *js = json_object_new_object();
109 
110  VuoText tableAsCsv = VuoTable_serialize(value, VuoTableFormat_Csv);
111  json_object_object_add(js, "csv", json_object_new_string(tableAsCsv));
112  VuoRetain(tableAsCsv);
113  VuoRelease(tableAsCsv);
114 
115  return js;
116 }
117 
121 char * VuoTable_getSummary(const VuoTable value)
122 {
123  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)value.data;
124 
125  const size_t maxTableRows = 4; // not counting ellipsis
126  const size_t maxTableColumns = 4; //
127 
128  ostringstream oss;
129  oss << "<table>";
130 
131  for (size_t i = 0; i < value.rowCount && i < maxTableRows; ++i)
132  {
133  oss << "<tr>";
134 
135  for (size_t j = 0; j < value.columnCount && j < maxTableColumns; ++j)
136  {
137  const char *dataValue = "";
138  if (i < (*data).size() && j < (*data)[i].size() && (*data)[i][j])
139  dataValue = (*data)[i][j];
140  oss << "<td>" << dataValue << "</td>";
141  }
142 
143  if (value.columnCount > maxTableColumns)
144  oss << "<td>…</td>";
145 
146  oss << "</tr>";
147  }
148 
149  if (value.rowCount > maxTableRows)
150  {
151  size_t ellipsisColumn = (value.columnCount > maxTableColumns ? 1 : 0);
152  oss << "<tr><td colspan=\"" << MIN(value.columnCount, maxTableColumns + ellipsisColumn) << "\">…</td></tr>";
153  }
154 
155  oss << "</table>";
156 
157  return VuoText_format("%lu row%s, %lu column%s<br>%s",
158  value.rowCount, value.rowCount == 1 ? "" : "s",
159  value.columnCount, value.columnCount == 1 ? "" : "s",
160  oss.str().c_str());
161 }
162 
163 
168 {
169  VuoTable table = { new vector< vector<VuoText> >, 0, 0 };
170  VuoRegister(table.data, deleteData);
171  return table;
172 }
173 
174 
179 {
180 public:
182 
185  vector< vector<VuoText> > *tableData;
188 
189  bool taken;
190 
191  ParserContext(void)
192  {
193  tableData = new vector< vector<VuoText> >;
194  atFirstColumn = true;
195  taken = false;
196  }
197 
198  ~ParserContext(void)
199  {
200  if (! taken)
201  delete tableData;
202  }
203 };
204 
208 static void parserGotItem(void *item, size_t numBytes, void *userData)
209 {
210  VuoText itemText = VuoText_makeFromData((unsigned char *)item, numBytes);
211  ParserContext *ctx = (ParserContext *)userData;
212 
213  if (ctx->atFirstColumn)
214  {
215  ctx->tableData->push_back( vector<VuoText>() );
216  ctx->atFirstColumn = false;
217  }
218 
219  ctx->tableData->back().push_back(itemText);
220 }
221 
225 static void parserGotLine(int lineEnd, void *userData)
226 {
227  ParserContext *ctx = (ParserContext *)userData;
228 
229  ctx->atFirstColumn = true;
230 }
231 
236 {
237  struct csv_parser parser;
238  unsigned char options = CSV_APPEND_NULL;
239 
240  int ret = csv_init(&parser, options);
241  if (ret)
242  {
243  VUserLog("Error: Couldn't initialize CSV/TSV parser.");
244  return VuoTable_makeEmpty();
245  }
246 
247  if (format == VuoTableFormat_Tsv)
248  csv_set_delim(&parser, CSV_TAB);
249 
250  ParserContext ctx;
251 
252  size_t numBytes = VuoText_byteCount(text);
253  size_t numBytesParsed = csv_parse(&parser, text, numBytes, parserGotItem, parserGotLine, &ctx);
254  if (numBytesParsed != numBytes)
255  {
256  VUserLog("Error: Couldn't parse CSV/TSV text: %s", csv_strerror(csv_error(&parser)));
257  csv_free(&parser);
258  return VuoTable_makeEmpty();
259  }
260 
261  ret = csv_fini(&parser, parserGotItem, parserGotLine, &ctx);
262  if (ret)
263  {
264  VUserLog("Error: Couldn't parse CSV/TSV text (or finalize parser): %s", csv_strerror(csv_error(&parser)));
265  csv_free(&parser);
266  return VuoTable_makeEmpty();
267  }
268 
269  csv_free(&parser);
270  ctx.taken = true;
271 
272  size_t rowCount = ctx.tableData->size();
273  size_t columnCount = 0;
274  for (vector< vector<VuoText> >::iterator i = ctx.tableData->begin(); i != ctx.tableData->end(); ++i)
275  columnCount = MAX((*i).size(), columnCount);
276 
277  VuoTable table = { (void *)ctx.tableData, rowCount, columnCount };
278  VuoRegister(table.data, deleteData);
279  return table;
280 }
281 
282 
287 {
288  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
289 
290  // Calculate the sizes of the strings to be written.
291 
292  vector< vector<size_t> > srcBytesForData( (*data).size() );
293  vector< vector<size_t> > dstBytesForData( (*data).size() );
294  size_t dstBytesTotal = 0;
295 
296  for (size_t i = 0; i < table.rowCount; ++i)
297  {
298  if (i < (*data).size())
299  {
300  srcBytesForData[i].resize( (*data)[i].size() );
301  dstBytesForData[i].resize( (*data)[i].size() );
302  }
303 
304  for (size_t j = 0; j < table.columnCount; ++j)
305  {
306  if (i < (*data).size() && j < (*data)[i].size())
307  {
308  srcBytesForData[i][j] = VuoText_byteCount( (*data)[i][j] );
309  dstBytesForData[i][j] = csv_write(NULL, 0, (*data)[i][j], srcBytesForData[i][j]);
310  dstBytesTotal += dstBytesForData[i][j];
311  }
312 
313  ++dstBytesTotal; // delimiter or newline
314  }
315  }
316 
317  // Write the strings.
318 
319  char delimiter = (format == VuoTableFormat_Tsv ? CSV_TAB : CSV_COMMA);
320  char newline = '\n';
321 
322  char *dst = (char *)malloc(dstBytesTotal);
323  char *dstPtr = dst;
324 
325  for (size_t i = 0; i < table.rowCount; ++i)
326  {
327  for (size_t j = 0; j < table.columnCount; ++j)
328  {
329  if (i < (*data).size() && j < (*data)[i].size())
330  {
331  size_t numBytesWritten = csv_write(dstPtr, dstBytesForData[i][j], (*data)[i][j], srcBytesForData[i][j]);
332  dstPtr += numBytesWritten;
333  }
334 
335  *dstPtr = (j+1 < table.columnCount ? delimiter : newline);
336  ++dstPtr;
337  }
338  }
339 
340  if (dstPtr > dst)
341  --dstPtr;
342  *dstPtr = 0;
343 
344  VuoText text = VuoText_make(dst);
345  free(dst);
346  return text;
347 }
348 
349 
354 static VuoInteger getIndexForHeader(VuoTable table, VuoText header, bool isColumnHeader)
355 {
356  if (VuoText_isEmpty(header))
357  return 0;
358 
359  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
360 
361  VuoTextComparison containsCaseInsensitive = {VuoTextComparison_Contains, false};
362 
363  if (isColumnHeader)
364  {
365  for (size_t i = 0; i < table.columnCount; ++i)
366  if (! (*data).empty() && i < (*data)[0].size() && VuoText_compare((*data)[0][i], containsCaseInsensitive, header))
367  return i+1;
368  }
369  else
370  {
371  for (size_t i = 0; i < table.rowCount; ++i)
372  if (i < (*data).size() && ! (*data)[i].empty() && VuoText_compare((*data)[i][0], containsCaseInsensitive, header))
373  return i+1;
374  }
375 
376  return 0;
377 }
378 
382 static VuoInteger getClampedIndex(VuoTable table, VuoInteger index, bool isColumnIndex)
383 {
384  VuoInteger maxIndex = (isColumnIndex ? table.columnCount : table.rowCount); // converts from size_t to VuoInteger
385  return MAX(1, MIN(maxIndex, index));
386 }
387 
388 
393 {
395 
401 
405  bool operator() (pair<size_t, VuoText> first, pair<size_t, VuoText> second)
406  {
407  if (sortOrder == VuoSortOrder_Descending)
408  swap(first, second);
409 
410  if (sortType == VuoTextSort_TextCaseSensitive)
411  return VuoText_isLessThan(first.second, second.second);
412  else if (sortType == VuoTextSort_Number)
413  return VuoText_isLessThanNumeric(first.second, second.second);
414  else if (sortType == VuoTextSort_Date)
415  {
416  VuoTime firstTime = VuoTime_makeFromUnknownFormat(first.second);
417  VuoTime secondTime = VuoTime_makeFromUnknownFormat(second.second);
418  return VuoTime_isLessThan(firstTime, secondTime);
419  }
420  else
421  return VuoText_isLessThanCaseInsensitive(first.second, second.second);
422  }
423 };
424 
435 VuoTable VuoTable_sort_VuoInteger(VuoTable table, VuoInteger columnIndex, VuoTextSort sortType, VuoSortOrder sortOrder, bool firstRowIsHeader)
436 {
437  columnIndex = getClampedIndex(table, columnIndex, true); // indexed from 1
438  size_t firstDataRow = (firstRowIsHeader ? 1 : 0); // indexed from 0
439 
440  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
441 
442  vector< pair<size_t, VuoText> > keyColumn;
443  for (size_t i = firstDataRow; i < table.rowCount; ++i)
444  {
445  if (i < (*data).size() && columnIndex-1 < (*data)[i].size())
446  keyColumn.push_back( make_pair(i, (*data)[i][columnIndex-1]) );
447  else
448  keyColumn.push_back( make_pair(i, "") );
449  }
450 
451  ColumnSort columnSort;
452  columnSort.sortType = sortType;
453  columnSort.sortOrder = sortOrder;
454  stable_sort(keyColumn.begin(), keyColumn.end(), columnSort);
455 
456  if (firstRowIsHeader)
457  keyColumn.insert(keyColumn.begin(), make_pair(0, "") );
458 
459  vector< vector<VuoText> > *sortedData = new vector< vector<VuoText> >(table.rowCount);
460  for (size_t i = 0; i < table.rowCount; ++i)
461  (*sortedData)[i].resize(table.columnCount);
462 
463  for (size_t i = 0; i < table.rowCount; ++i)
464  for (size_t j = 0; j < table.columnCount; ++j)
465  if (i < (*data).size() && j < (*data)[i].size())
466  (*sortedData)[i][j] = (*data)[ keyColumn[i].first ][j];
467 
468  VuoTable sortedTable = { sortedData, table.rowCount, table.columnCount };
469  VuoRegister(sortedData, deleteData);
470  return sortedTable;
471 }
472 
479 VuoTable VuoTable_sort_VuoText(VuoTable table, VuoText columnHeader, VuoTextSort sortType, VuoSortOrder sortOrder, bool firstRowIsHeader)
480 {
481  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
482  if (columnIndex == 0)
483  return table;
484 
485  return VuoTable_sort_VuoInteger(table, columnIndex, sortType, sortOrder, firstRowIsHeader);
486 }
487 
488 
493 {
494  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
495 
496  vector< vector<VuoText> > *transposedData = new vector< vector<VuoText> >(table.columnCount);
497  for (size_t i = 0; i < table.columnCount; ++i)
498  (*transposedData)[i].resize(table.rowCount);
499 
500  for (size_t i = 0; i < table.rowCount; ++i)
501  for (size_t j = 0; j < table.columnCount; ++j)
502  if (i < (*data).size() && j < (*data)[i].size())
503  (*transposedData)[j][i] = (*data)[i][j];
504 
505  VuoTable transposedTable = { transposedData, table.columnCount, table.rowCount };
506  VuoRegister(transposedData, deleteData);
507  return transposedTable;
508 }
509 
510 
515 VuoList_VuoText VuoTable_getRow_VuoInteger(VuoTable table, VuoInteger rowIndex, bool includeHeader)
516 {
517  if (table.rowCount == 0)
518  return VuoListCreate_VuoText();
519 
520  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
521 
522  rowIndex = getClampedIndex(table, rowIndex, false);
523 
524  size_t startIndex = (includeHeader ? 0 : 1);
525  size_t count = table.columnCount - startIndex;
526 
528  for (size_t i = startIndex; i < table.columnCount; ++i)
529  if (rowIndex-1 < (*data).size() && i < (*data)[rowIndex-1].size())
530  VuoListSetValue_VuoText(row, (*data)[rowIndex-1][i], i+1-startIndex, false);
531 
532  return row;
533 }
534 
539 VuoList_VuoText VuoTable_getRow_VuoText(VuoTable table, VuoText rowHeader, bool includeHeader)
540 {
541  VuoInteger rowIndex = getIndexForHeader(table, rowHeader, false);
542  if (rowIndex == 0)
543  return VuoListCreate_VuoText();
544 
545  return VuoTable_getRow_VuoInteger(table, rowIndex, includeHeader);
546 }
547 
552 VuoList_VuoText VuoTable_getColumn_VuoInteger(VuoTable table, VuoInteger columnIndex, bool includeHeader)
553 {
554  if (table.rowCount == 0)
555  return VuoListCreate_VuoText();
556 
557  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
558 
559  columnIndex = getClampedIndex(table, columnIndex, true);
560 
561  size_t startIndex = (includeHeader ? 0 : 1);
562  size_t count = table.rowCount - startIndex;
563 
564  VuoList_VuoText column = VuoListCreateWithCount_VuoText(count, NULL);
565  for (size_t i = startIndex; i < table.rowCount; ++i)
566  if (i < (*data).size() && columnIndex-1 < (*data)[i].size())
567  VuoListSetValue_VuoText(column, (*data)[i][columnIndex-1], i+1-startIndex, false);
568 
569  return column;
570 }
571 
576 VuoList_VuoText VuoTable_getColumn_VuoText(VuoTable table, VuoText columnHeader, bool includeHeader)
577 {
578  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
579  if (columnIndex == 0)
580  return VuoListCreate_VuoText();
581 
582  return VuoTable_getColumn_VuoInteger(table, columnIndex, includeHeader);
583 }
584 
589 {
590  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
591  if ((*data).empty())
592  return NULL;
593 
594  rowIndex = getClampedIndex(table, rowIndex, false);
595  columnIndex = getClampedIndex(table, columnIndex, true);
596 
597  return (*data)[rowIndex-1][columnIndex-1];
598 }
599 
604 {
605  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
606  if (columnIndex == 0)
607  return NULL;
608 
609  return VuoTable_getItem_VuoInteger_VuoInteger(table, rowIndex, columnIndex);
610 }
611 
616 {
617  VuoInteger rowIndex = getIndexForHeader(table, rowHeader, false);
618  if (rowIndex == 0)
619  return NULL;
620 
621  return VuoTable_getItem_VuoInteger_VuoInteger(table, rowIndex, columnIndex);
622 }
623 
628 {
629  VuoInteger rowIndex = getIndexForHeader(table, rowHeader, false);
630  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
631  if (rowIndex == 0 || columnIndex == 0)
632  return NULL;
633 
634  return VuoTable_getItem_VuoInteger_VuoInteger(table, rowIndex, columnIndex);
635 }
636 
641 {
642  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
643  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
644 
645  vector< vector<VuoText> >::iterator rowIter;
646  size_t rowIndex;
647  if (position == VuoListPosition_Beginning)
648  {
649  rowIter = (*data).begin();
650  rowIndex = 0;
651  }
652  else
653  {
654  rowIter = (*data).end();
655  rowIndex = table.rowCount;
656  }
657 
658  unsigned long count = VuoListGetCount_VuoText(values);
659  VuoText *rowArray = VuoListGetData_VuoText(values);
660 
661  (*data).insert(rowIter, vector<VuoText>(count));
662  for (unsigned long i = 0; i < count; ++i)
663  (*data)[rowIndex][i] = rowArray[i];
664 
665  VuoTable newTable = { data, table.rowCount + 1, MAX(table.columnCount, count) };
666  VuoRegister(newTable.data, deleteData);
667  return newTable;
668 }
669 
674 {
675  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
676  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
677 
678  unsigned long count = VuoListGetCount_VuoText(values);
679  VuoText *columnArray = VuoListGetData_VuoText(values);
680 
681  if ((*data).size() < count)
682  (*data).resize(count);
683 
684  for (size_t i = 0; i < count; ++i)
685  {
686  if (position == VuoListPosition_End && (*data)[i].size() < table.columnCount)
687  (*data)[i].resize(table.columnCount);
688 
689  vector<VuoText>::iterator columnIter = (position == VuoListPosition_Beginning ? (*data)[i].begin() : (*data)[i].end());
690  (*data)[i].insert(columnIter, columnArray[i]);
691  }
692 
693  VuoTable newTable = { data, MAX(table.rowCount, count), table.columnCount + 1 };
694  VuoRegister(newTable.data, deleteData);
695  return newTable;
696 }
697 
701 VuoTable VuoTable_changeRow_VuoInteger(VuoTable table, VuoInteger rowIndex, VuoList_VuoText newValues, bool preserveHeader)
702 {
703  if (table.rowCount == 0)
704  return table;
705 
706  rowIndex = getClampedIndex(table, rowIndex, false);
707 
708  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
709  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
710 
711  unsigned long newValuesCount = VuoListGetCount_VuoText(newValues);
712  VuoText *rowArray = VuoListGetData_VuoText(newValues);
713 
714  size_t firstDataIndex = (preserveHeader ? 1 : 0);
715 
716  (*data)[rowIndex-1].resize(newValuesCount+firstDataIndex);
717 
718  if (preserveHeader && ! (*origData)[rowIndex-1].empty())
719  (*data)[rowIndex-1][0] = (*origData)[rowIndex-1][0];
720 
721  for (size_t i = 0; i < newValuesCount; ++i)
722  (*data)[rowIndex-1][i+firstDataIndex] = rowArray[i];
723 
724  VuoTable newTable = { data, table.rowCount, MAX(table.columnCount, newValuesCount+firstDataIndex) };
725  VuoRegister(newTable.data, deleteData);
726  return newTable;
727 }
728 
732 VuoTable VuoTable_changeRow_VuoText(VuoTable table, VuoText rowHeader, VuoList_VuoText newValues, bool preserveHeader)
733 {
734  VuoInteger rowIndex = getIndexForHeader(table, rowHeader, false);
735  if (rowIndex == 0)
736  return table;
737 
738  return VuoTable_changeRow_VuoInteger(table, rowIndex, newValues, preserveHeader);
739 }
740 
744 VuoTable VuoTable_changeColumn_VuoInteger(VuoTable table, VuoInteger columnIndex, VuoList_VuoText newValues, bool preserveHeader)
745 {
746  if (table.columnCount == 0)
747  return table;
748 
749  columnIndex = getClampedIndex(table, columnIndex, true);
750 
751  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
752  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
753 
754  unsigned long newValuesCount = VuoListGetCount_VuoText(newValues);
755  VuoText *columnArray = VuoListGetData_VuoText(newValues);
756 
757  size_t firstDataIndex = (preserveHeader ? 1 : 0);
758 
759  if ((*data).size() < newValuesCount+firstDataIndex)
760  (*data).resize(newValuesCount+firstDataIndex);
761 
762  for (size_t i = 0; i < newValuesCount+firstDataIndex; ++i)
763  if ((*data)[i].size() < columnIndex)
764  (*data)[i].resize(columnIndex);
765 
766  if (preserveHeader && (*origData)[0].size() > columnIndex-1)
767  (*data)[0][columnIndex-1] = (*origData)[0][columnIndex-1];
768 
769  for (size_t i = 0; i < MAX(table.rowCount-firstDataIndex, newValuesCount); ++i)
770  (*data)[i+firstDataIndex][columnIndex-1] = (i < newValuesCount ? columnArray[i] : NULL);
771 
772  VuoTable newTable = { data, MAX(table.rowCount, newValuesCount+firstDataIndex), table.columnCount };
773  VuoRegister(newTable.data, deleteData);
774  return newTable;
775 }
776 
780 VuoTable VuoTable_changeColumn_VuoText(VuoTable table, VuoText columnHeader, VuoList_VuoText newValues, bool preserveHeader)
781 {
782  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
783  if (columnIndex == 0)
784  return table;
785 
786  return VuoTable_changeColumn_VuoInteger(table, columnIndex, newValues, preserveHeader);
787 }
788 
793 {
794  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
795  if ((*origData).empty())
796  return table;
797 
798  rowIndex = getClampedIndex(table, rowIndex, false);
799  columnIndex = getClampedIndex(table, columnIndex, true);
800 
801  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
802  (*data)[rowIndex-1][columnIndex-1] = newValue;
803 
804  VuoTable newTable = { data, table.rowCount, table.columnCount };
805  VuoRegister(newTable.data, deleteData);
806  return newTable;
807 
808 }
809 
814 {
815  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
816  if (columnIndex == 0)
817  return table;
818 
819  return VuoTable_changeItem_VuoInteger_VuoInteger(table, rowIndex, columnIndex, newValue);
820 }
821 
826 {
827  VuoInteger rowIndex = getIndexForHeader(table, rowHeader, false);
828  if (rowIndex == 0)
829  return table;
830 
831  return VuoTable_changeItem_VuoInteger_VuoInteger(table, rowIndex, columnIndex, newValue);
832 }
833 
838 {
839  VuoInteger rowIndex = getIndexForHeader(table, rowHeader, false);
840  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
841  if (rowIndex == 0 || columnIndex == 0)
842  return table;
843 
844  return VuoTable_changeItem_VuoInteger_VuoInteger(table, rowIndex, columnIndex, newValue);
845 }
846 
851 {
852  if (table.rowCount == 0)
853  return table;
854 
855  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
856  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
857 
858  vector< vector<VuoText> >::iterator rowIter = (position == VuoListPosition_Beginning ? (*data).begin() : (*data).end() - 1);
859  (*data).erase(rowIter);
860 
861  VuoTable newTable = { data, table.rowCount - 1, table.columnCount };
862  VuoRegister(newTable.data, deleteData);
863  return newTable;
864 }
865 
870 {
871  if (table.columnCount == 0)
872  return table;
873 
874  vector< vector<VuoText> > *origData = (vector< vector<VuoText> > *)table.data;
875  vector< vector<VuoText> > *data = new vector< vector<VuoText> >(*origData);
876 
877  for (size_t i = 0; i < table.rowCount; ++i)
878  {
879  if (position == VuoListPosition_End && (*data)[i].size() < table.columnCount)
880  continue;
881 
882  vector<VuoText>::iterator columnIter = (position == VuoListPosition_Beginning ? (*data)[i].begin() : (*data)[i].end() - 1);
883  (*data)[i].erase(columnIter);
884  }
885 
886  VuoTable newTable = { data, table.rowCount, table.columnCount - 1 };
887  VuoRegister(newTable.data, deleteData);
888  return newTable;
889 }
890 
896 VuoList_VuoText VuoTable_findFirstMatchingRow_VuoInteger(VuoTable table, VuoInteger columnIndex, VuoText valueToFind, VuoTextComparison valueComparison, bool includeHeader)
897 {
898  if (table.rowCount == 0)
899  return nullptr;
900 
901  auto rows = static_cast<vector<vector<VuoText>>*>(table.data);
902 
903  columnIndex = getClampedIndex(table, columnIndex, true);
904 
905  auto foundRow = find_if(rows->begin(), rows->end(), [columnIndex, valueComparison, valueToFind](vector<VuoText> row) {
906  return VuoText_compare(row[columnIndex - 1], valueComparison, valueToFind);
907  });
908 
909  if (foundRow == rows->end())
910  return nullptr;
911 
912  size_t startIndex = (includeHeader ? 0 : 1);
913  size_t count = foundRow->size() - startIndex;
914 
915  VuoList_VuoText outputRow = VuoListCreateWithCount_VuoText(count, NULL);
916  for (size_t i = startIndex; i < table.columnCount; ++i)
917  VuoListSetValue_VuoText(outputRow, (*foundRow)[i], i + 1 - startIndex, false);
918 
919  return outputRow;
920 }
921 
927 VuoList_VuoText VuoTable_findFirstMatchingRow_VuoText(VuoTable table, VuoText columnHeader, VuoText valueToFind, VuoTextComparison valueComparison, bool includeHeader)
928 {
929  VuoInteger columnIndex = getIndexForHeader(table, columnHeader, true);
930  if (columnIndex == 0)
931  return nullptr;
932 
933  return VuoTable_findFirstMatchingRow_VuoInteger(table, columnIndex, valueToFind, valueComparison, includeHeader);
934 }
935 
940 {
941  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
942  for (vector< vector<VuoText> >::iterator i = data->begin(); i != data->end(); ++i)
943  for (vector<VuoText>::iterator j = i->begin(); j != i->end(); ++j)
944  VuoRetain(*j);
945 
946  VuoRetain(table.data);
947 }
948 
953 {
954  vector< vector<VuoText> > *data = (vector< vector<VuoText> > *)table.data;
955  for (vector< vector<VuoText> >::iterator i = data->begin(); i != data->end(); ++i)
956  for (vector<VuoText>::iterator j = i->begin(); j != i->end(); ++j)
957  VuoRelease(*j);
958 
959  VuoRelease(table.data);
960 }