Program Listing for File Handles.hpp
↰ Return to documentation for file (include/lvr2/geometry/Handles.hpp)
/*
* Handles.hpp
*
* @date 15.06.2017
* @author Lukas Kalbertodt <lukas.kalbertodt@gmail.com>
*/
#ifndef LVR2_GEOMETRY_HANDLES_H_
#define LVR2_GEOMETRY_HANDLES_H_
#include <cstdint>
#include <functional>
#include "lvr2/util/BaseHandle.hpp"
namespace lvr2
{
using Index = pmp::IndexType;
// Note on strongly typed handles:
//
// You might ask: Why do we need that many classes for handles? Wouldn't one
// be enough? Or you go even further: if every handle is just a simple integer,
// why not store the integer directly. Well, it all comes down to "strong
// typing".
//
// Type systems are the main way for compilers to notice that a program is
// faulty. While compiler errors are just annoying in the first few years of
// learning how to program, they become very useful later on. When writing
// software, humans will make mistakes -- that's just a fact. The question is
// WHEN we want to notice those mistakes. There are a few possibilities here:
//
// - while compiling
// - while executing unit tests
// - in production
//
// No one wants to notice bugs when already running software in production. Thus
// we want to notice our mistakes earlier. Since this whole library clearly
// doesn't care about unit tests, mistakes can only be noticed either at
// compile time or when the developer executes the program.
//
// Well, now the fun parts. When you use a language with a sufficiently
// powerful type system (as C++) and if you are correctly using this type
// system, you can avoid many huge classes of bugs! The compiler will tell you
// right away, when you made a mistake.
//
// So with these strongly typed handles, you cannot falsely assign an EdgeHandle
// to a FaceHandle -- it will result in a compiler error. If you were using
// simple integers, the compiler wouldn't notice and you would have to track
// down the bug manually. Not so great.
//
// Apart from that: it makes reading code so much easier, as you know exactly
// what a specific parameter is for.
using EdgeHandle = pmp::Edge;
using FaceHandle = pmp::Face;
using VertexHandle = pmp::Vertex;
class ClusterHandle : public BaseHandle
{
using BaseHandle::BaseHandle;
};
class TextureHandle : public BaseHandle
{
using BaseHandle::BaseHandle;
};
class OptionalEdgeHandle : public BaseOptionalHandle<EdgeHandle>
{
using BaseOptionalHandle<EdgeHandle>::BaseOptionalHandle;
};
class OptionalFaceHandle : public BaseOptionalHandle<FaceHandle>
{
using BaseOptionalHandle<FaceHandle>::BaseOptionalHandle;
};
class OptionalVertexHandle : public BaseOptionalHandle<VertexHandle>
{
using BaseOptionalHandle<VertexHandle>::BaseOptionalHandle;
};
class OptionalClusterHandle : public BaseOptionalHandle<ClusterHandle>
{
using BaseOptionalHandle<ClusterHandle>::BaseOptionalHandle;
};
inline std::ostream& operator<<(std::ostream& os, const ClusterHandle& h)
{
return (os << 'c' << h.idx());
}
inline std::ostream& operator<<(std::ostream& os, const OptionalEdgeHandle& h)
{
if (h)
{
os << "E" << h.unwrap().idx();
}
else
{
os << "E⊥";
}
return os;
}
inline std::ostream& operator<<(std::ostream& os, const OptionalFaceHandle& h)
{
if (h)
{
os << "F" << h.unwrap().idx();
}
else
{
os << "F⊥";
}
return os;
}
inline std::ostream& operator<<(std::ostream& os, const OptionalVertexHandle& h)
{
if (h)
{
os << "V" << h.unwrap().idx();
}
else
{
os << "V⊥";
}
return os;
}
inline std::ostream& operator<<(std::ostream& os, const OptionalClusterHandle& h)
{
if (h)
{
os << "C" << h.unwrap().idx();
}
else
{
os << "C⊥";
}
return os;
}
} // namespace lvr2
namespace std
{
IMPL_HANDLE_HASH(lvr2::ClusterHandle);
IMPL_HANDLE_HASH(lvr2::TextureHandle);
} // namespace std
#endif /* LVR2_GEOMETRY_HANDLES_H_ */