1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkStringArray.cxx
5   Language:  C++
6 
7   Copyright 2004 Sandia Corporation.
8   Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9   license for use of this work by or on behalf of the
10   U.S. Government. Redistribution and use in source and binary forms, with
11   or without modification, are permitted provided that this Notice and any
12   statement of authorship are reproduced on all copies.
13 
14 =========================================================================*/
15 
16 // We do not provide a definition for the copy constructor or
17 // operator=.  Block the warning.
18 #ifdef _MSC_VER
19 # pragma warning (disable: 4661)
20 #endif
21 
22 #include "vtkStdString.h"
23 
24 #include "vtkStringArray.h"
25 
26 #include "vtkArrayIteratorTemplate.h"
27 #include "vtkCharArray.h"
28 #include "vtkIdList.h"
29 #include "vtkIdTypeArray.h"
30 #include "vtkObjectFactory.h"
31 #include "vtkSortDataArray.h"
32 
33 #include <utility>
34 #include <algorithm>
35 #include <map>
36 #include <vector>
37 
38 // Map containing updates to a vtkStringArray that have occurred
39 // since we last build the vtkStringArrayLookup.
40 typedef std::multimap<vtkStdString, vtkIdType> vtkStringCachedUpdates;
41 
42 namespace
43 {
__anon12f65f220202(void *ptr) 44 auto DefaultDeleteFunction = [](void *ptr) {
45   delete[] reinterpret_cast<vtkStdString *>(ptr);
46 };
47 }
48 
49 //-----------------------------------------------------------------------------
50 class vtkStringArrayLookup
51 {
52 public:
vtkStringArrayLookup()53   vtkStringArrayLookup() : Rebuild(true)
54   {
55     this->SortedArray = nullptr;
56     this->IndexArray = nullptr;
57   }
~vtkStringArrayLookup()58   ~vtkStringArrayLookup()
59   {
60     if (this->SortedArray)
61     {
62       this->SortedArray->Delete();
63       this->SortedArray = nullptr;
64     }
65     if (this->IndexArray)
66     {
67       this->IndexArray->Delete();
68       this->IndexArray = nullptr;
69     }
70   }
71   vtkStringArray* SortedArray;
72   vtkIdList* IndexArray;
73   vtkStringCachedUpdates CachedUpdates;
74   bool Rebuild;
75 };
76 
77 vtkStandardNewMacro(vtkStringArray);
78 
79 //-----------------------------------------------------------------------------
80 
vtkStringArray()81 vtkStringArray::vtkStringArray()
82 {
83   this->Array = nullptr;
84   this->DeleteFunction = DefaultDeleteFunction;
85   this->Lookup = nullptr;
86 }
87 
88 //-----------------------------------------------------------------------------
89 
~vtkStringArray()90 vtkStringArray::~vtkStringArray()
91 {
92   if (this->DeleteFunction)
93   {
94     this->DeleteFunction(this->Array);
95   }
96   delete this->Lookup;
97 }
98 
99 //-----------------------------------------------------------------------------
NewIterator()100 vtkArrayIterator* vtkStringArray::NewIterator()
101 {
102   vtkArrayIteratorTemplate<vtkStdString>* iter =
103     vtkArrayIteratorTemplate<vtkStdString>::New();
104   iter->Initialize(this);
105   return iter;
106 }
107 
108 //-----------------------------------------------------------------------------
109 // This method lets the user specify data to be held by the array.  The
110 // array argument is a pointer to the data.  size is the size of
111 // the array supplied by the user.  Set save to 1 to keep the class
112 // from deleting the array when it cleans up or reallocates memory.
113 // The class uses the actual array provided; it does not copy the data
114 // from the suppled array.
SetArray(vtkStdString * array,vtkIdType size,int save,int deleteMethod)115 void vtkStringArray::SetArray(vtkStdString *array, vtkIdType size, int save,
116                               int deleteMethod)
117 {
118   if (this->Array && this->DeleteFunction)
119   {
120     vtkDebugMacro (<< "Deleting the array...");
121     this->DeleteFunction(this->Array);
122   }
123   else
124   {
125     vtkDebugMacro (<<"Warning, array not deleted, but will point to new array.");
126   }
127 
128   vtkDebugMacro(<<"Setting array to: " << array);
129 
130   this->Array = array;
131   this->Size = size;
132   this->MaxId = size-1;
133 
134   if(save!=0)
135   {
136     this->DeleteFunction = nullptr;
137   }
138   else if(deleteMethod == VTK_DATA_ARRAY_DELETE ||
139           deleteMethod == VTK_DATA_ARRAY_USER_DEFINED)
140   {
141     this->DeleteFunction = DefaultDeleteFunction;
142   }
143   else if(deleteMethod == VTK_DATA_ARRAY_ALIGNED_FREE)
144   {
145 #ifdef _WIN32
146     this->DeleteFunction = _aligned_free;
147 #else
148     this->DeleteFunction = free;
149 #endif
150   }
151   else if(deleteMethod == VTK_DATA_ARRAY_FREE)
152   {
153     this->DeleteFunction = free;
154   }
155 
156   this->DataChanged();
157 }
158 
159 //-----------------------------------------------------------------------------
SetArrayFreeFunction(void (* callback)(void *))160 void vtkStringArray::SetArrayFreeFunction(void (*callback)(void *))
161 {
162   this->DeleteFunction = callback;
163 }
164 
165 //-----------------------------------------------------------------------------
166 // Allocate memory for this array. Delete old storage only if necessary.
167 
Allocate(vtkIdType sz,vtkIdType)168 vtkTypeBool vtkStringArray::Allocate(vtkIdType sz, vtkIdType)
169 {
170   if(sz > this->Size)
171   {
172     if(this->DeleteFunction)
173     {
174       this->DeleteFunction(this->Array);
175     }
176 
177     this->Size = ( sz > 0 ? sz : 1);
178     this->Array = new vtkStdString[this->Size];
179     if(!this->Array)
180     {
181       return 0;
182     }
183     this->DeleteFunction = DefaultDeleteFunction;
184   }
185 
186   this->MaxId = -1;
187   this->DataChanged();
188 
189   return 1;
190 }
191 
192 //-----------------------------------------------------------------------------
193 // Release storage and reset array to initial state.
194 
Initialize()195 void vtkStringArray::Initialize()
196 {
197   if(this->DeleteFunction)
198   {
199     this->DeleteFunction(this->Array);
200   }
201   this->Array = nullptr;
202   this->Size = 0;
203   this->MaxId = -1;
204   this->DeleteFunction = DefaultDeleteFunction;
205   this->DataChanged();
206 }
207 
208 //-----------------------------------------------------------------------------
209 // Deep copy of another string array.
210 
DeepCopy(vtkAbstractArray * aa)211 void vtkStringArray::DeepCopy(vtkAbstractArray* aa)
212 {
213   // Do nothing on a nullptr input.
214   if(!aa)
215   {
216     return;
217   }
218 
219   // Avoid self-copy.
220   if(this == aa)
221   {
222     return;
223   }
224 
225   // If data type does not match, we can't copy.
226   if(aa->GetDataType() != this->GetDataType())
227   {
228     vtkErrorMacro(<< "Incompatible types: tried to copy an array of type "
229                   << aa->GetDataTypeAsString()
230                   << " into a string array ");
231     return;
232   }
233 
234   vtkStringArray *fa = vtkArrayDownCast<vtkStringArray>( aa );
235   if ( fa == nullptr )
236   {
237     vtkErrorMacro(<< "Shouldn't Happen: Couldn't downcast array into a vtkStringArray." );
238     return;
239   }
240 
241   // Free our previous memory.
242   if(this->DeleteFunction)
243   {
244     this->DeleteFunction(this->Array);
245   }
246 
247   // Copy the given array into new memory.
248   this->MaxId = fa->GetMaxId();
249   this->Size = fa->GetSize();
250   this->DeleteFunction = DefaultDeleteFunction;
251   this->Array = new vtkStdString[this->Size];
252 
253   for (int i = 0; i < this->Size; ++i)
254   {
255     this->Array[i] = fa->Array[i];
256   }
257   this->DataChanged();
258 }
259 
260 //-----------------------------------------------------------------------------
261 // Interpolate array value from other array value given the
262 // indices and associated interpolation weights.
263 // This method assumes that the two arrays are of the same time.
InterpolateTuple(vtkIdType i,vtkIdList * ptIndices,vtkAbstractArray * source,double * weights)264 void vtkStringArray::InterpolateTuple(vtkIdType i, vtkIdList *ptIndices,
265     vtkAbstractArray* source,  double* weights)
266 {
267   if (this->GetDataType() != source->GetDataType())
268   {
269     vtkErrorMacro("Cannot CopyValue from array of type "
270       << source->GetDataTypeAsString());
271     return;
272   }
273 
274   if (ptIndices->GetNumberOfIds() == 0)
275   {
276     // nothing to do.
277     return;
278   }
279 
280   // We use nearest neighbour for interpolating strings.
281   // First determine which is the nearest neighbour using the weights-
282   // it's the index with maximum weight.
283   vtkIdType nearest = ptIndices->GetId(0);
284   double max_weight = weights[0];
285   for (int k=1; k < ptIndices->GetNumberOfIds(); k++)
286   {
287     if (weights[k] > max_weight)
288     {
289       nearest = ptIndices->GetId(k);
290       max_weight = weights[k];
291     }
292   }
293 
294   this->InsertTuple(i, nearest, source);
295 }
296 
297 //-----------------------------------------------------------------------------
298 // Interpolate value from the two values, p1 and p2, and an
299 // interpolation factor, t. The interpolation factor ranges from (0,1),
300 // with t=0 located at p1. This method assumes that the three arrays are of
301 // the same type. p1 is value at index id1 in fromArray1, while, p2 is
302 // value at index id2 in fromArray2.
InterpolateTuple(vtkIdType i,vtkIdType id1,vtkAbstractArray * source1,vtkIdType id2,vtkAbstractArray * source2,double t)303 void vtkStringArray::InterpolateTuple(vtkIdType i, vtkIdType id1,
304   vtkAbstractArray* source1, vtkIdType id2, vtkAbstractArray* source2,
305   double t)
306 {
307   if (source1->GetDataType() != VTK_STRING ||
308     source2->GetDataType() != VTK_STRING)
309   {
310     vtkErrorMacro("All arrays to InterpolateValue() must be of same type.");
311     return;
312   }
313 
314   if (t >= 0.5)
315   {
316     // Use p2
317     this->InsertTuple(i, id2, source2);
318   }
319   else
320   {
321     // Use p1.
322     this->InsertTuple(i, id1, source1);
323   }
324 }
325 
326 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)327 void vtkStringArray::PrintSelf(ostream& os, vtkIndent indent)
328 {
329   this->Superclass::PrintSelf(os,indent);
330   if(this->Array)
331   {
332     os << indent << "Array: " << this->Array << "\n";
333   }
334   else
335   {
336     os << indent << "Array: (null)\n";
337   }
338 }
339 
340 //-----------------------------------------------------------------------------
341 // Protected function does "reallocate"
342 
ResizeAndExtend(vtkIdType sz)343 vtkStdString * vtkStringArray::ResizeAndExtend(vtkIdType sz)
344 {
345   vtkStdString * newArray;
346   vtkIdType newSize;
347 
348   if(sz > this->Size)
349   {
350     // Requested size is bigger than current size.  Allocate enough
351     // memory to fit the requested size and be more than double the
352     // currently allocated memory.
353     newSize = (this->Size+1) + sz;
354   }
355   else if (sz == this->Size)
356   {
357     // Requested size is equal to current size.  Do nothing.
358     return this->Array;
359   }
360   else
361   {
362     // Requested size is smaller than current size.  Squeeze the
363     // memory.
364     newSize = sz;
365   }
366 
367   if(newSize <= 0)
368   {
369     this->Initialize();
370     return nullptr;
371   }
372 
373   newArray = new vtkStdString[newSize];
374   if(!newArray)
375   {
376     vtkErrorMacro("Cannot allocate memory\n");
377     return nullptr;
378   }
379 
380   if(this->Array)
381   {
382     // can't use memcpy here
383     vtkIdType numCopy = (newSize < this->Size ? newSize : this->Size);
384     for (vtkIdType i = 0; i < numCopy; ++i)
385     {
386       newArray[i] = this->Array[i];
387     }
388     if(this->DeleteFunction)
389     {
390       this->DeleteFunction(this->Array);
391     }
392   }
393 
394   if(newSize < this->Size)
395   {
396     this->MaxId = newSize-1;
397   }
398   this->Size = newSize;
399   this->Array = newArray;
400   this->DeleteFunction = DefaultDeleteFunction;
401 
402   this->DataChanged();
403   return this->Array;
404 }
405 
406 //-----------------------------------------------------------------------------
Resize(vtkIdType sz)407 vtkTypeBool vtkStringArray::Resize(vtkIdType sz)
408 {
409   vtkStdString * newArray;
410   vtkIdType newSize = sz;
411 
412   if(newSize == this->Size)
413   {
414     return 1;
415   }
416 
417   if(newSize <= 0)
418   {
419     this->Initialize();
420     return 1;
421   }
422 
423   newArray = new vtkStdString[newSize];
424   if(!newArray)
425   {
426     vtkErrorMacro(<< "Cannot allocate memory\n");
427     return 0;
428   }
429 
430   if(this->Array)
431   {
432     vtkIdType numCopy = (newSize < this->Size ? newSize : this->Size);
433 
434     for (vtkIdType i = 0; i < numCopy; ++i)
435     {
436       newArray[i] = this->Array[i];
437     }
438 
439     if (this->DeleteFunction)
440     {
441       this->DeleteFunction = DefaultDeleteFunction;
442       this->DeleteFunction(this->Array);
443 
444     }
445   }
446 
447   if(newSize < this->Size)
448   {
449     this->MaxId = newSize-1;
450   }
451   this->Size = newSize;
452   this->Array = newArray;
453   this->DeleteFunction = DefaultDeleteFunction;
454   this->DataChanged();
455   return 1;
456 }
457 
458 
459 //-----------------------------------------------------------------------------
SetNumberOfValues(vtkIdType number)460 void vtkStringArray::SetNumberOfValues(vtkIdType number)
461 {
462   this->Allocate(number);
463   this->MaxId = number - 1;
464   this->DataChanged();
465 }
466 
467 //-----------------------------------------------------------------------------
WritePointer(vtkIdType id,vtkIdType number)468 vtkStdString * vtkStringArray::WritePointer(vtkIdType id,
469                                      vtkIdType number)
470 {
471   vtkIdType newSize=id+number;
472   if ( newSize > this->Size )
473   {
474     this->ResizeAndExtend(newSize);
475   }
476   if ( (--newSize) > this->MaxId )
477   {
478     this->MaxId = newSize;
479   }
480   this->DataChanged();
481   return this->Array + id;
482 }
483 
484 //-----------------------------------------------------------------------------
InsertValue(vtkIdType id,vtkStdString f)485 void vtkStringArray::InsertValue(vtkIdType id, vtkStdString f)
486 {
487   if ( id >= this->Size )
488   {
489     if (!this->ResizeAndExtend(id+1))
490     {
491       return;
492     }
493   }
494   this->Array[id] = f;
495   if ( id > this->MaxId )
496   {
497     this->MaxId = id;
498   }
499   this->DataElementChanged(id);
500 }
501 
502 //-----------------------------------------------------------------------------
InsertNextValue(vtkStdString f)503 vtkIdType vtkStringArray::InsertNextValue(vtkStdString f)
504 {
505   this->InsertValue (++this->MaxId,f);
506   this->DataElementChanged(this->MaxId);
507   return this->MaxId;
508 }
509 
510 // ----------------------------------------------------------------------------
GetDataTypeSize(void)511 int vtkStringArray::GetDataTypeSize( void )
512 {
513   return static_cast<int>(sizeof(vtkStdString));
514 }
515 
516 // ----------------------------------------------------------------------------
GetActualMemorySize(void)517 unsigned long vtkStringArray::GetActualMemorySize( void )
518 {
519   size_t totalSize = 0;
520   size_t  numPrims = static_cast<size_t>(this->GetSize());
521 
522   for (size_t i = 0; i < numPrims; ++i)
523   {
524     totalSize += sizeof( vtkStdString );
525     totalSize += this->Array[i].size() *sizeof( vtkStdString::value_type );
526   }
527 
528   return static_cast<unsigned long>(
529     ceil(static_cast<double>(totalSize) / 1024.0 )); // kibibytes
530 }
531 
532 // ----------------------------------------------------------------------------
GetDataSize()533 vtkIdType vtkStringArray::GetDataSize()
534 {
535   size_t size = 0;
536   size_t numStrs = static_cast<size_t>(this->GetMaxId() + 1);
537   for(size_t i=0; i < numStrs; i++)
538   {
539     size += this->Array[i].size() + 1;
540     // (+1) for termination character.
541   }
542   return static_cast<vtkIdType>(size);
543 }
544 
545 // ----------------------------------------------------------------------------
546 // Set the tuple at the ith location using the jth tuple in the source array.
547 // This method assumes that the two arrays have the same type
548 // and structure. Note that range checking and memory allocation is not
549 // performed; use in conjunction with SetNumberOfTuples() to allocate space.
SetTuple(vtkIdType i,vtkIdType j,vtkAbstractArray * source)550 void vtkStringArray::SetTuple(vtkIdType i, vtkIdType j,
551   vtkAbstractArray* source)
552 {
553   vtkStringArray* sa = vtkArrayDownCast<vtkStringArray>(source);
554   if (!sa)
555   {
556     vtkWarningMacro("Input and outputs array data types do not match.");
557     return ;
558   }
559 
560   vtkIdType loci = i * this->NumberOfComponents;
561   vtkIdType locj = j * sa->GetNumberOfComponents();
562   for (vtkIdType cur = 0; cur < this->NumberOfComponents; cur++)
563   {
564     this->SetValue(loci + cur, sa->GetValue(locj + cur));
565   }
566   this->DataChanged();
567 }
568 
569 // ----------------------------------------------------------------------------
570 // Insert the jth tuple in the source array, at ith location in this array.
571 // Note that memory allocation is performed as necessary to hold the data.
InsertTuple(vtkIdType i,vtkIdType j,vtkAbstractArray * source)572 void vtkStringArray::InsertTuple(vtkIdType i, vtkIdType j,
573   vtkAbstractArray* source)
574 {
575   vtkStringArray* sa = vtkArrayDownCast<vtkStringArray>(source);
576   if (!sa)
577   {
578     vtkWarningMacro("Input and outputs array data types do not match.");
579     return ;
580   }
581 
582   vtkIdType loci = i * this->NumberOfComponents;
583   vtkIdType locj = j * sa->GetNumberOfComponents();
584   for (vtkIdType cur = 0; cur < this->NumberOfComponents; cur++)
585   {
586     this->InsertValue(loci + cur, sa->GetValue(locj + cur));
587   }
588   this->DataChanged();
589 }
590 
591 // ----------------------------------------------------------------------------
InsertTuples(vtkIdList * dstIds,vtkIdList * srcIds,vtkAbstractArray * source)592 void vtkStringArray::InsertTuples(vtkIdList *dstIds, vtkIdList *srcIds,
593                                   vtkAbstractArray *source)
594 {
595   vtkStringArray* sa = vtkArrayDownCast<vtkStringArray>(source);
596   if (!sa)
597   {
598     vtkWarningMacro("Input and outputs array data types do not match.");
599     return ;
600   }
601 
602   if (this->NumberOfComponents != source->GetNumberOfComponents())
603   {
604     vtkWarningMacro("Input and output component sizes do not match.");
605     return;
606   }
607 
608   vtkIdType numIds = dstIds->GetNumberOfIds();
609   if (srcIds->GetNumberOfIds() != numIds)
610   {
611     vtkWarningMacro("Input and output id array sizes do not match.");
612     return;
613   }
614 
615   for (vtkIdType idIndex = 0; idIndex < numIds; ++idIndex)
616   {
617     vtkIdType numComp = this->NumberOfComponents;
618     vtkIdType srcLoc = srcIds->GetId(idIndex) * this->NumberOfComponents;
619     vtkIdType dstLoc = dstIds->GetId(idIndex) * this->NumberOfComponents;
620     while (numComp-- > 0)
621     {
622       this->InsertValue(dstLoc++, sa->GetValue(srcLoc++));
623     }
624   }
625 
626   this->DataChanged();
627 }
628 
629 // ----------------------------------------------------------------------------
InsertTuples(vtkIdType dstStart,vtkIdType n,vtkIdType srcStart,vtkAbstractArray * source)630 void vtkStringArray::InsertTuples(vtkIdType dstStart, vtkIdType n,
631                                   vtkIdType srcStart, vtkAbstractArray *source)
632 {
633   vtkStringArray* sa = vtkArrayDownCast<vtkStringArray>(source);
634   if (!sa)
635   {
636     vtkWarningMacro("Input and outputs array data types do not match.");
637     return ;
638   }
639 
640   if (this->NumberOfComponents != source->GetNumberOfComponents())
641   {
642     vtkWarningMacro("Input and output component sizes do not match.");
643     return;
644   }
645 
646   vtkIdType srcEnd = srcStart + n;
647   if (srcEnd > source->GetNumberOfTuples())
648   {
649     vtkWarningMacro("Source range exceeds array size (srcStart=" << srcStart
650                     << ", n=" << n << ", numTuples="
651                     << source->GetNumberOfTuples() << ").");
652     return;
653   }
654 
655   for (vtkIdType i = 0; i < n; ++i)
656   {
657     vtkIdType numComp = this->NumberOfComponents;
658     vtkIdType srcLoc = (srcStart + i) * this->NumberOfComponents;
659     vtkIdType dstLoc = (dstStart + i) * this->NumberOfComponents;
660     while (numComp-- > 0)
661     {
662       this->InsertValue(dstLoc++, sa->GetValue(srcLoc++));
663     }
664   }
665 
666   this->DataChanged();
667 }
668 
669 // ----------------------------------------------------------------------------
670 // Insert the jth tuple in the source array, at the end in this array.
671 // Note that memory allocation is performed as necessary to hold the data.
672 // Returns the location at which the data was inserted.
InsertNextTuple(vtkIdType j,vtkAbstractArray * source)673 vtkIdType vtkStringArray::InsertNextTuple(vtkIdType j,
674                                           vtkAbstractArray* source)
675 {
676   vtkStringArray* sa = vtkArrayDownCast<vtkStringArray>(source);
677   if (!sa)
678   {
679     vtkWarningMacro("Input and outputs array data types do not match.");
680     return -1;
681   }
682 
683   vtkIdType locj = j * sa->GetNumberOfComponents();
684   for (vtkIdType cur = 0; cur < this->NumberOfComponents; cur++)
685   {
686     this->InsertNextValue(sa->GetValue(locj + cur));
687   }
688   this->DataChanged();
689   return (this->GetNumberOfTuples()-1);
690 }
691 
692 // ----------------------------------------------------------------------------
GetValue(vtkIdType id)693 vtkStdString& vtkStringArray::GetValue( vtkIdType id )
694 {
695   return this->Array[id];
696 }
697 
698 // ----------------------------------------------------------------------------
GetTuples(vtkIdList * indices,vtkAbstractArray * aa)699 void vtkStringArray::GetTuples(vtkIdList *indices, vtkAbstractArray *aa)
700 {
701   if (aa == nullptr)
702   {
703     vtkErrorMacro(<<"GetTuples: Output array is null!");
704     return;
705   }
706 
707   vtkStringArray *output = vtkArrayDownCast<vtkStringArray>(aa);
708 
709   if (output == nullptr)
710   {
711     vtkErrorMacro(<< "Can't copy values from a string array into an array "
712                   << "of type " << aa->GetDataTypeAsString());
713     return;
714   }
715 
716   for (vtkIdType i = 0; i < indices->GetNumberOfIds(); ++i)
717   {
718     vtkIdType index = indices->GetId(i);
719     output->SetValue(i, this->GetValue(index));
720   }
721 }
722 
723 // ----------------------------------------------------------------------------
GetTuples(vtkIdType startIndex,vtkIdType endIndex,vtkAbstractArray * aa)724 void vtkStringArray::GetTuples(vtkIdType startIndex,
725                           vtkIdType endIndex,
726                           vtkAbstractArray *aa)
727 {
728   if (aa == nullptr)
729   {
730     vtkErrorMacro(<<"GetTuples: Output array is null!");
731     return;
732   }
733 
734   vtkStringArray *output = vtkArrayDownCast<vtkStringArray>(aa);
735 
736   if (output == nullptr)
737   {
738     vtkErrorMacro(<< "Can't copy values from a string array into an array "
739                   << "of type " << aa->GetDataTypeAsString());
740     return;
741   }
742 
743   for (vtkIdType i = 0; i < (endIndex - startIndex) + 1; ++i)
744   {
745     vtkIdType index = startIndex + i;
746     output->SetValue(i, this->GetValue(index));
747   }
748 }
749 
750 //-----------------------------------------------------------------------------
UpdateLookup()751 void vtkStringArray::UpdateLookup()
752 {
753   if (!this->Lookup)
754   {
755     this->Lookup = new vtkStringArrayLookup();
756     this->Lookup->SortedArray = vtkStringArray::New();
757     this->Lookup->IndexArray = vtkIdList::New();
758   }
759   if (this->Lookup->Rebuild)
760   {
761     int numComps = this->GetNumberOfComponents();
762     vtkIdType numTuples = this->GetNumberOfTuples();
763     this->Lookup->SortedArray->Initialize();
764     this->Lookup->SortedArray->SetNumberOfComponents(numComps);
765     this->Lookup->SortedArray->SetNumberOfTuples(numTuples);
766     this->Lookup->IndexArray->SetNumberOfIds(numComps*numTuples);
767     std::vector<std::pair<vtkStdString, vtkIdType> > v;
768     for (vtkIdType i = 0; i < numComps*numTuples; i++)
769     {
770       v.push_back(std::pair<vtkStdString, vtkIdType>(this->Array[i], i));
771     }
772     std::sort(v.begin(), v.end());
773     for (vtkIdType i = 0; i < numComps*numTuples; i++)
774     {
775       this->Lookup->SortedArray->SetValue(i, v[i].first);
776       this->Lookup->IndexArray->SetId(i, v[i].second);
777     }
778     this->Lookup->Rebuild = false;
779     this->Lookup->CachedUpdates.clear();
780   }
781 }
782 
783 //-----------------------------------------------------------------------------
LookupValue(vtkVariant var)784 vtkIdType vtkStringArray::LookupValue(vtkVariant var)
785 {
786   return this->LookupValue(var.ToString());
787 }
788 
789 //-----------------------------------------------------------------------------
LookupValue(vtkVariant var,vtkIdList * ids)790 void vtkStringArray::LookupValue(vtkVariant var, vtkIdList* ids)
791 {
792   this->LookupValue(var.ToString(), ids);
793 }
794 
795 //-----------------------------------------------------------------------------
LookupValue(const vtkStdString & value)796 vtkIdType vtkStringArray::LookupValue(const vtkStdString& value)
797 {
798   this->UpdateLookup();
799 
800   // First look into the cached updates, to see if there were any
801   // cached changes. Find an equivalent element in the set of cached
802   // indices for this value. Some of the indices may have changed
803   // values since the cache was built, so we need to do this equality
804   // check.
805   typedef vtkStringCachedUpdates::iterator CacheIterator;
806   CacheIterator cached    = this->Lookup->CachedUpdates.lower_bound(value),
807                 cachedEnd = this->Lookup->CachedUpdates.end();
808   while (cached != cachedEnd)
809   {
810     // Check that we are still in the same equivalence class as the
811     // value.
812     if (value == cached->first)
813     {
814       // Check that the value in the original array hasn't changed.
815       vtkStdString currentValue = this->GetValue(cached->second);
816       if (value == currentValue)
817       {
818         return cached->second;
819       }
820     }
821     else
822     {
823       break;
824     }
825 
826     ++cached;
827   }
828 
829   int numComps = this->Lookup->SortedArray->GetNumberOfComponents();
830   vtkIdType numTuples = this->Lookup->SortedArray->GetNumberOfTuples();
831   vtkStdString* ptr = this->Lookup->SortedArray->GetPointer(0);
832   vtkStdString* ptrEnd = ptr + numComps*numTuples;
833   vtkStdString* found = std::lower_bound(ptr, ptrEnd, value);
834 
835   // Find an index with a matching value. Non-matching values might
836   // show up here when the underlying value at that index has been
837   // changed (so the sorted array is out-of-date).
838   vtkIdType offset = static_cast<vtkIdType>(found - ptr);
839   while (found != ptrEnd)
840   {
841     // Check whether we still have a value equivalent to what we're
842     // looking for.
843     if (value == *found)
844     {
845       // Check that the value in the original array hasn't changed.
846       vtkIdType index = this->Lookup->IndexArray->GetId(offset);
847       vtkStdString currentValue = this->GetValue(index);
848       if (value == currentValue)
849       {
850         return index;
851       }
852     }
853     else
854     {
855       break;
856     }
857 
858     ++found;
859     ++offset;
860   }
861 
862   return -1;
863 }
864 
865 //-----------------------------------------------------------------------------
LookupValue(const vtkStdString & value,vtkIdList * ids)866 void vtkStringArray::LookupValue(const vtkStdString& value, vtkIdList* ids)
867 {
868   this->UpdateLookup();
869   ids->Reset();
870 
871   // First look into the cached updates, to see if there were any
872   // cached changes. Find an equivalent element in the set of cached
873   // indices for this value. Some of the indices may have changed
874   // values since the cache was built, so we need to do this equality
875   // check.
876   typedef vtkStringCachedUpdates::iterator CacheIterator;
877   std::pair<CacheIterator, CacheIterator> cached
878     = this->Lookup->CachedUpdates.equal_range(value);
879   while (cached.first != cached.second)
880   {
881     // Check that the value in the original array hasn't changed.
882     vtkStdString currentValue = this->GetValue(cached.first->second);
883     if (cached.first->first == currentValue)
884     {
885       ids->InsertNextId(cached.first->second);
886     }
887 
888     ++cached.first;
889   }
890 
891   // Perform a binary search of the sorted array using STL equal_range.
892   int numComps = this->GetNumberOfComponents();
893   vtkIdType numTuples = this->GetNumberOfTuples();
894   vtkStdString* ptr = this->Lookup->SortedArray->GetPointer(0);
895   std::pair<vtkStdString*,vtkStdString*> found =
896     std::equal_range(ptr, ptr + numComps*numTuples, value);
897 
898   // Add the indices of the found items to the ID list.
899   vtkIdType offset = static_cast<vtkIdType>(found.first - ptr);
900   while (found.first != found.second)
901   {
902     // Check that the value in the original array hasn't changed.
903     vtkIdType index = this->Lookup->IndexArray->GetId(offset);
904     vtkStdString currentValue = this->GetValue(index);
905     if (*found.first == currentValue)
906     {
907       ids->InsertNextId(index);
908     }
909 
910     ++found.first;
911     ++offset;
912   }
913 }
914 
915 //-----------------------------------------------------------------------------
DataChanged()916 void vtkStringArray::DataChanged()
917 {
918   if (this->Lookup)
919   {
920     this->Lookup->Rebuild = true;
921   }
922 }
923 
924 //----------------------------------------------------------------------------
DataElementChanged(vtkIdType id)925 void vtkStringArray::DataElementChanged(vtkIdType id)
926 {
927   if (this->Lookup)
928   {
929       if (this->Lookup->Rebuild)
930       {
931         // We're already going to rebuild the lookup table. Do nothing.
932         return;
933       }
934 
935       if (this->Lookup->CachedUpdates.size() >
936           static_cast<size_t>(this->GetNumberOfTuples()/10))
937       {
938         // At this point, just rebuild the full table.
939         this->Lookup->Rebuild = true;
940       }
941       else
942       {
943         // Insert this change into the set of cached updates
944         std::pair<const vtkStdString, vtkIdType>
945           value(this->GetValue(id), id);
946         this->Lookup->CachedUpdates.insert(value);
947       }
948   }
949 }
950 
951 //-----------------------------------------------------------------------------
ClearLookup()952 void vtkStringArray::ClearLookup()
953 {
954   delete this->Lookup;
955   this->Lookup = nullptr;
956 }
957 
958 
959 // ----------------------------------------------------------------------------
960 
961 //
962 //
963 // Below here are interface methods to allow values to be inserted as
964 // const char * instead of vtkStdString.  Yes, they're trivial.  The
965 // wrapper code needs them.
966 //
967 //
968 
969 
SetValue(vtkIdType id,const char * value)970 void vtkStringArray::SetValue( vtkIdType id, const char *value )
971 {
972   if( value )
973   {
974     this->SetValue( id, vtkStdString(value) );
975   }
976 }
977 
InsertValue(vtkIdType id,const char * value)978 void vtkStringArray::InsertValue( vtkIdType id, const char *value )
979 {
980   if( value )
981   {
982     this->InsertValue( id, vtkStdString( value ) );
983   }
984 }
985 
SetVariantValue(vtkIdType id,vtkVariant value)986 void vtkStringArray::SetVariantValue( vtkIdType id, vtkVariant value )
987 {
988   this->SetValue( id, value.ToString() );
989 }
990 
InsertVariantValue(vtkIdType id,vtkVariant value)991 void vtkStringArray::InsertVariantValue( vtkIdType id, vtkVariant value )
992 {
993   this->InsertValue( id, value.ToString() );
994 }
995 
InsertNextValue(const char * value)996 vtkIdType vtkStringArray::InsertNextValue( const char *value )
997 {
998   if( value )
999   {
1000     return this->InsertNextValue( vtkStdString( value ) );
1001   }
1002   return this->MaxId;
1003 }
1004 
LookupValue(const char * value)1005 vtkIdType vtkStringArray::LookupValue( const char *value )
1006 {
1007   if( value )
1008   {
1009     return this->LookupValue( vtkStdString( value ) );
1010   }
1011   return -1;
1012 }
1013 
LookupValue(const char * value,vtkIdList * ids)1014 void vtkStringArray::LookupValue( const char *value, vtkIdList* ids)
1015 {
1016   if( value )
1017   {
1018     this->LookupValue( vtkStdString( value ), ids);
1019     return;
1020   }
1021   ids->Reset();
1022 }
1023 
1024 // ----------------------------------------------------------------------------
1025 
1026