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