Are OpenMesh iterators changed when adding elements? - openmesh

Do existing OpenMesh iterators change, when I add elements?
Example code:
auto vh1 = mesh.vertex_handle(0);
auto vh2 = mesh.vertex_handle(1);
auto vh3 = mesh.vertex_handle(2);
for(auto fh: mesh.faces()) {
mesh.add_face(vh1, vh2, vh3);
}
I did not find something about this in the documentation.
Example seem to work, but I want to know if it's undefined behavior or if OpenMesh promises to make sure that the iterator does not change during the loop.

OpenMesh does not change the iterators when you add elements, but I don't think OpenMesh gives you a promise on that.
OpenMesh iterators are basically just ints. (They hold a SmartHandle and some information about which elements should be skipped. A SmartHandle holds a Handle and a reference to the mesh. A Handle is just a strongly typed integer.)
Incrementing the iterator will just increment the integer (until an element is reached which should not be skipped). Since you always access elements via the mesh and a handle the relocation of the actual memory that stores the elements is not a problem.
Note that depending on how you code your loop the new element may or may not be iterated over.
for (auto it = mesh_.vertices_begin(); it != mesh_.vertices_end(); ++it)
{
mesh_.add_vertex(point);
}
The loop above will include the newly added vertex as mesh_.vertices_end() is reevaluated for each comparison and will thus include the newly added elements. This leads to an infinite loop in that case.
auto end = mesh_.vertices.end();
for (auto it = mesh_.vertices_begin(); it != end; ++it)
{
mesh_.add_vertex(point);
}
In this case, the newly added elements will not be contained in the loop. That is because end is evaluated only once in the beginning and basically just holds the number of vertices the mesh had at that point.
for (auto vh : mesh_.vertices())
{
mesh_.add_vertex(point);
}
This will behave as the second version as here, too, vertices_end() is only evaluated once in the beginning.
Deletion
Since it was brought up in the other answer I want to quickly talk about deletion.
Deleting an element will only mark it as deleted. Thus, deleting elements while iterating over the elements is fine.
When you delete elements which have not been visited yet, they may or may not be iterated over later. If you use skipping iterators the deleted elements will be skipped, otherwise they won't be skipped.
For OpenMesh 7.0 or newer for (auto fh : mesh_.faces()) {...} will not include deleted elements.
Instead for (auto fh : mesh_.all_faces()) {...} will include deleted elements.
Garbage Collection
You should probably not call garbage collection inside your loop. If you have deleted elements, garbage collection will cause two problems. First, it reduces the size of the container storing the elements. Thus, versions of the loop that evaluate the end iterator once will likely run too far and crash.
If you use the other version of the loop or manage to create more new elements than you remove, you still have the problem that garbage collection will move elements from the back into the spots of the elements that were marked as deleted. Thus, you will miss those elements if they are moved to spots that you already passed.

One can search typedef std::vector< in openmesh,then you can find it. But
add_face won't reallocation this iterators, because the new vertex handle or face handle will push_back to the end of this vector. Meanwhile , in order to have a high-efficient search speed, Openmesh builds at least three layers of iterators, and the vector we discuss is only the bottom of them. The middle or top iterators, I use them by assemble functions,so I'm not sure it will be reallocated/invalidated or not, and you can find them in PolyConnectivity.hh and TriConnectivity.hh.

Related

Mutable data types that use stack allocation

Based on my earlier question, I understand the benefit of using stack allocation. Suppose I have an array of arrays. For example, A is a list of matrices and each element A[i] is a 1x3 matrix. The length of A and the dimension of A[i] are known at run time (given by the user). Each A[i] is a matrix of Float64 and this is also known at run time. However, through out the program, I will be modifying the values of A[i] element by element. What data structure can also allow me to use stack allocation? I tried StaticArrays but it doesn't allow me to modify a static array.
StaticArrays defines MArray (MVector, MMatrix) types that are fixed-size and mutable. If you use these there's a higher chance of the compiler determining that they can be stack-allocated, but it's not guaranteed. Moreover, since the pattern you're using is that you're passing the mutable state vector into a function which presumably modifies it, it's not going to be valid or helpful to stack allocate that anyway. If you're going to allocate state once and modify it throughout the program, it doesn't really matter if it is heap or stack allocated—stack allocation is only a big win for objects that are allocated, used locally and then don't escape the local scope, so they can be “freed” simply by popping the stack.
From the code snippet you showed in the linked question, the state vector is allocated in the outer function, test_for_loop, which shouldn't be a big deal since it's done once at the beginning of execution. Using a variably sized state vector to index into an array with a splat (...) might be an issue, however, and that's done in test_function. Using something with fixed size like MVector might be better for that. It might, however, be better still, to use a state tuple and return a new rather than mutated state tuple at the end. The compiler is very good at turning that kind of thing into very efficient code because of immutability.
Note that by convention test_function should be called test_function! since it modifies its M argument and even more so if it modifies the state vector.
I would also note that this isn't a great question/answer pair since it's not standalone at all and really just a continuation of your other question. StackOverflow isn't very good for this kind of iterative question/discussion interaction, I'm afraid.

Is there a container that I can add and remove from both ends

Is there a container in C++ I could use to add elements in both ends, not just back or just front, but would like to add in either end. And similarly remove elements from any end, not from just one. Maybe in STLs or Boost?
You can portably add an element x to the front of a sequence container (vector/deque/list) via v.insert(v.begin(), x). However, for vector this is an O(n) operation (this is why vector does not have a convenient push_front operation) and it relocates all the existing elements. If you don't want existing elements to be relocated, deque or list may be a better fit.

Implementing a fixed run-time size array. Should move ctor and swap throw exceptions?

The problem with std::array is that it has a fixed compile-time size. I want a container that can be created with a dynamic size, but that size stays fixed throughout the life of the container (so std::vector won't work, because push_back will increment the size by 1).
I am wondering how to implement this. I tried writing a class that contains an internal std::vector for storage, and only exposes the members of std::vector that don't change the size. My question is regarding the copy/move assignment operators, as well as the swap member function. Usually, move assignment is declared as noexcept. However, before assignment, I have to check if the lhs and the rhs are of the same size. If they are not, I must throw an exception, because otherwise, assigning rhs to lhs would change the size of lhs, which I don't want. The same happens with swap, which in my implementation is noexcept for the same reason.
I know I am going against usual advice to make swap and move assignment noexcept (Item 14 of Scott Meyers' Modern Effective C++), so I am wondering if this is good design? Or is there a better way to implement a fixed runtime size container?
Example: Suppose I have defined my fixed size container with the name FixedSizeArray<T>.
auto arr1 = FixedSizeArray<double>(4, 1.0)
The last line of code defined a FixedSizeArray containing doubles of size 4. Now define another:
auto arr2 = FixedSizeArray<double>(10, 1.0)
Should the following line:
arr1 = std::move(arr2)
throw? What about:
arr1.swap(arr2)
Do declare move assignement and swap as noexcept. But don't throw on mismatched sizes...
Since your arrays are fixed-size, ending up assigning or swapping two arrays of different sizes can't possibly work, in any circumstances. It's not an exceptional condition, it's a situation where the program doesn't know what it's doing. That's a case for an assertion.

vector --> concurrent_vector migration + OpenGL restriction

I need to speed-up some calculation and result of calculation then used to draw OpenGL model.
Major speed-up archived when I changed std::vector to Concurrency::concurrent_vector and used parallel_for instead of just for loops.
This vector (or concurrent_vector) calculated in for (or parallel_for) loop and contains vertices for OpenGL to visualize.
It is fine using std::vector because OpenGL rendering procedure relies on the fact that std::vector keeps it's items in sequence which is not a case with concurrent_vector. Code runs something like this:
glVertexPointer(3, GL_FLOAT, 0, &vectorWithVerticesData[0]);
To generate concurrent_vector and copy it to std::vector is too expensive since there are lot of items.
So, the question is: I'd like to use OpenGL arrays, but also like to use concurrent_vector which is incompatible with OpenGL output.
Any suggestions?
You're trying to use a data structure that doesn't store its elements contiguously in an API that requires contiguous storage. Well, one of those has to give, and it's not going to be OpenGL. GL isn't going to walk concurrent_vector's data structure (not if you like performance).
So your option is to not use non-sequential objects.
I can only guess at what you're doing (since you didn't provide example code for the generator), so that limits what I can advise. If your parallel_for iterates for a fixed number of times (by "fixed", I mean a value that is known immediately before parallel_for executes. It doesn't change based on how many times you've iterated), then you can just use a regular vector.
Simply size the vector with vector::size. This will value-initialize the elements, which means that every element exists. You can now perform your parallel_for loop, but instead of using push_back or whatever, you simply copy the element directly into its location in the output. I think parallel_for can iterate over the actual vector iterators, but I'm not positive. Either way, it doesn't matter; you won't get any race conditions unless you try to set the same element from different threads.

Is this linear search implementation actually useful?

In Matters Computational I found this interesting linear search implementation (it's actually my Java implementation ;-)):
public static int linearSearch(int[] a, int key) {
int high = a.length - 1;
int tmp = a[high];
// put a sentinel at the end of the array
a[high] = key;
int i = 0;
while (a[i] != key) {
i++;
}
// restore original value
a[high] = tmp;
if (i == high && key != tmp) {
return NOT_CONTAINED;
}
return i;
}
It basically uses a sentinel, which is the searched for value, so that you always find the value and don't have to check for array boundaries. The last element is stored in a temp variable, and then the sentinel is placed at the last position. When the value is found (remember, it is always found due to the sentinel), the original element is restored and the index is checked if it represents the last index and is unequal to the searched for value. If that's the case, -1 (NOT_CONTAINED) is returned, otherwise the index.
While I found this implementation really clever, I wonder if it is actually useful. For small arrays, it seems to be always slower, and for large arrays it only seems to be faster when the value is not found. Any ideas?
EDIT
The original implementation was written in C++, so that could make a difference.
It's not thread-safe, for example, you can lose your a[high] value through having a second thread start after the first has changed a[high] to key, so will record key to tmp, and finish after the first thread has restored a[high] to its original value. The second thread will restore a[high] to what it first saw, which was the first thread's key.
It's also not useful in java, since the JVM will include bounds checks on your array, so your while loop is checking that you're not going past the end of your array anyway.
Will you ever notice any speed increase from this? No
Will you notice a lack of readability? Yes
Will you notice an unnecessary array mutation that might cause concurrency issues? Yes
Premature optimization is the root of all evil.
Doesn't seem particularly useful. The "innovation" here is just to get rid of the iteration test by combining it with the match test. Modern processors spend 0 time on iteration checks these days (all the computation and branching gets done in parallel with the match test code).
In any case, binary search kicks the ass of this code on large arrays, and is comparable on small arrays. Linear search is so 1960s.
See also the 'finding a tiger in africa' joke.
Punchline = An experienced programmer places a tiger in cairo so that the search terminates.
A sentinel search goes back to Knuth. It value is that it reduces the number of tests in a loop from two ("does the key match? Am I at the end?") to just one.
Yes, its useful, in the sense that it should significantly reduce search times for modest size unordered arrays, by virtue of eliminating conditional branch mispredictions. This also reduces insertion times (code not shown by the OP) for such arrays, because you don't have to order the items.
If you have larger arrays of ordered items, a binary search will be faster, at the cost of larger insertion time to ensure the array is ordered.
For even larger sets, a hash table will be the fastest.
The real question is what is the distribution of sizes of your arrays?
Yes - it does because while loop doesn't have 2 comparisons as opposed to standard search.
It is twice as fast.It is given as optimization in Knuth Vol 3.

Resources