PropertyContainer.hh 12.1 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1
/* ========================================================================= *
Jan Möbius's avatar
Jan Möbius committed
2 3
 *                                                                           *
 *                               OpenMesh                                    *
Jan Möbius's avatar
Jan Möbius committed
4
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
Jan Möbius's avatar
Typo  
Jan Möbius committed
5
 *           Department of Computer Graphics and Multimedia                  *
Jan Möbius's avatar
Jan Möbius committed
6 7
 *                          All rights reserved.                             *
 *                            www.openmesh.org                               *
Jan Möbius's avatar
Jan Möbius committed
8
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
9 10 11
 *---------------------------------------------------------------------------*
 * This file is part of OpenMesh.                                            *
 *---------------------------------------------------------------------------*
Jan Möbius's avatar
Jan Möbius committed
12
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
13 14 15
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
Jan Möbius's avatar
Jan Möbius committed
16
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
17 18
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
Jan Möbius's avatar
Jan Möbius committed
19
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
20 21 22
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
Jan Möbius's avatar
Jan Möbius committed
23
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
24 25 26
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
27
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
28 29 30 31 32 33 34 35 36 37 38
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39 40
 *                                                                           *
 * ========================================================================= */
41

42

Jan Möbius's avatar
Jan Möbius committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

#ifndef OPENMESH_PROPERTYCONTAINER
#define OPENMESH_PROPERTYCONTAINER

// Use static casts when not debugging
#ifdef NDEBUG
#define OM_FORCE_STATIC_CAST
#endif

#include <OpenMesh/Core/Utils/Property.hh>

//-----------------------------------------------------------------------------
namespace OpenMesh
{
//== FORWARDDECLARATIONS ======================================================
  class BaseKernel;

//== CLASS DEFINITION =========================================================
/// A a container for properties.
class PropertyContainer
{
public:

  //-------------------------------------------------- constructor / destructor

  PropertyContainer() {}
69
  virtual ~PropertyContainer() { std::for_each(properties_.begin(), properties_.end(), Delete()); }
Jan Möbius's avatar
Jan Möbius committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85


  //------------------------------------------------------------- info / access

  typedef std::vector<BaseProperty*> Properties;
  const Properties& properties() const { return properties_; }
  size_t size() const { return properties_.size(); }



  //--------------------------------------------------------- copy / assignment

  PropertyContainer(const PropertyContainer& _rhs) { operator=(_rhs); }

  PropertyContainer& operator=(const PropertyContainer& _rhs)
  {
86 87
    // The assignment below relies on all previous BaseProperty* elements having been deleted
    std::for_each(properties_.begin(), properties_.end(), Delete());
Jan Möbius's avatar
Jan Möbius committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
    properties_ = _rhs.properties_;
    Properties::iterator p_it=properties_.begin(), p_end=properties_.end();
    for (; p_it!=p_end; ++p_it)
      if (*p_it)
        *p_it = (*p_it)->clone();
    return *this;
  }



  //--------------------------------------------------------- manage properties

  template <class T>
  BasePropHandleT<T> add(const T&, const std::string& _name="<unknown>")
  {
    Properties::iterator p_it=properties_.begin(), p_end=properties_.end();
    int idx=0;
    for ( ; p_it!=p_end && *p_it!=NULL; ++p_it, ++idx ) {};
    if (p_it==p_end) properties_.push_back(NULL);
    properties_[idx] = new PropertyT<T>(_name);
    return BasePropHandleT<T>(idx);
  }


  template <class T>
  BasePropHandleT<T> handle(const T&, const std::string& _name) const
  {
    Properties::const_iterator p_it = properties_.begin();
    for (int idx=0; p_it != properties_.end(); ++p_it, ++idx)
    {
      if (*p_it != NULL &&
         (*p_it)->name() == _name  //skip deleted properties
// Skip type check
#ifndef OM_FORCE_STATIC_CAST
          && dynamic_cast<PropertyT<T>*>(properties_[idx]) != NULL //check type
#endif
         )
      {
        return BasePropHandleT<T>(idx);
      }
    }
    return BasePropHandleT<T>();
  }

  BaseProperty* property( const std::string& _name ) const
  {
    Properties::const_iterator p_it = properties_.begin();
    for (int idx=0; p_it != properties_.end(); ++p_it, ++idx)
    {
      if (*p_it != NULL && (*p_it)->name() == _name) //skip deleted properties
      {
        return *p_it;
      }
    }
    return NULL;
  }

  template <class T> PropertyT<T>& property(BasePropHandleT<T> _h)
  {
    assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size());
    assert(properties_[_h.idx()] != NULL);
#ifdef OM_FORCE_STATIC_CAST
    return *static_cast  <PropertyT<T>*> (properties_[_h.idx()]);
#else
    PropertyT<T>* p = dynamic_cast<PropertyT<T>*>(properties_[_h.idx()]);
    assert(p != NULL);
    return *p;
#endif
  }


  template <class T> const PropertyT<T>& property(BasePropHandleT<T> _h) const
  {
    assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size());
    assert(properties_[_h.idx()] != NULL);
#ifdef OM_FORCE_STATIC_CAST
    return *static_cast<PropertyT<T>*>(properties_[_h.idx()]);
#else
    PropertyT<T>* p = dynamic_cast<PropertyT<T>*>(properties_[_h.idx()]);
    assert(p != NULL);
    return *p;
#endif
  }


  template <class T> void remove(BasePropHandleT<T> _h)
  {
    assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size());
    delete properties_[_h.idx()];
    properties_[_h.idx()] = NULL;
  }


  void clear()
  {
183 184 185 186 187 188 189 190 191 192
	// Clear properties vector:
	// Replaced the old version with new one
	// which performs a swap to clear values and
	// deallocate memory.

	// Old version (changed 22.07.09) {
	// std::for_each(properties_.begin(), properties_.end(), Delete());
    // }

	std::for_each(properties_.begin(), properties_.end(), ClearAll());
Jan Möbius's avatar
Jan Möbius committed
193 194 195 196 197
  }


  //---------------------------------------------------- synchronize properties

198 199 200 201
/*
 * In C++11 an beyond we can introduce more efficient and more legible
 * implementations of the following methods.
 */
202
#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
203 204 205
  /**
   * Reserves space for \p _n elements in all property vectors.
   */
206 207 208 209 210
  void reserve(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(),
            [_n](BaseProperty* p) { if (p) p->reserve(_n); });
  }

211 212 213
  /**
   * Resizes all property vectors to the specified size.
   */
214 215 216 217 218
  void resize(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(),
            [_n](BaseProperty* p) { if (p) p->resize(_n); });
  }

219 220 221 222 223 224 225 226
  /**
   * Same as resize() but ignores property vectors that have a size larger
   * than \p _n.
   *
   * Use this method instead of resize() if you plan to frequently reduce
   * and enlarge the property container and you don't want to waste time
   * reallocating the property vectors every time.
   */
Hans-Christian Ebke's avatar
Hans-Christian Ebke committed
227 228 229 230 231
  void resize_if_smaller(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(),
            [_n](BaseProperty* p) { if (p && p->n_elements() < _n) p->resize(_n); });
  }

232 233 234 235
  /**
   * Swaps the items with index \p _i0 and index \p _i1 in all property
   * vectors.
   */
236 237 238 239 240
  void swap(size_t _i0, size_t _i1) const {
    std::for_each(properties_.begin(), properties_.end(),
            [_i0, _i1](BaseProperty* p) { if (p) p->swap(_i0, _i1); });
  }
#else
241 242 243
  /**
   * Reserves space for \p _n elements in all property vectors.
   */
Jan Möbius's avatar
Jan Möbius committed
244 245 246 247
  void reserve(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(), Reserve(_n));
  }

248 249 250
  /**
   * Resizes all property vectors to the specified size.
   */
Jan Möbius's avatar
Jan Möbius committed
251 252 253 254
  void resize(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(), Resize(_n));
  }

255 256 257 258 259 260 261 262
  /**
   * Same as \sa resize() but ignores property vectors that have a size
   * larger than \p _n.
   *
   * Use this method instead of \sa resize() if you plan to frequently reduce
   * and enlarge the property container and you don't want to waste time
   * reallocating the property vectors every time.
   */
Hans-Christian Ebke's avatar
Hans-Christian Ebke committed
263 264 265 266
  void resize_if_smaller(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n));
  }

267 268 269 270
  /**
   * Swaps the items with index \p _i0 and index \p _i1 in all property
   * vectors.
   */
Jan Möbius's avatar
Jan Möbius committed
271 272 273
  void swap(size_t _i0, size_t _i1) const {
    std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1));
  }
274
#endif
Jan Möbius's avatar
Jan Möbius committed
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324



protected: // generic add/get

  size_t _add( BaseProperty* _bp )
  {
    Properties::iterator p_it=properties_.begin(), p_end=properties_.end();
    size_t idx=0;
    for (; p_it!=p_end && *p_it!=NULL; ++p_it, ++idx) {};
    if (p_it==p_end) properties_.push_back(NULL);
    properties_[idx] = _bp;
    return idx;
  }

  BaseProperty& _property( size_t _idx )
  {
    assert( _idx < properties_.size());
    assert( properties_[_idx] != NULL);
    BaseProperty *p = properties_[_idx];
    assert( p != NULL );
    return *p;
  }

  const BaseProperty& _property( size_t _idx ) const
  {
    assert( _idx < properties_.size());
    assert( properties_[_idx] != NULL);
    BaseProperty *p = properties_[_idx];
    assert( p != NULL );
    return *p;
  }


  typedef Properties::iterator       iterator;
  typedef Properties::const_iterator const_iterator;
  iterator begin() { return properties_.begin(); }
  iterator end()   { return properties_.end(); }
  const_iterator begin() const { return properties_.begin(); }
  const_iterator end() const   { return properties_.end(); }

  friend class BaseKernel;

private:

  //-------------------------------------------------- synchronization functors

#ifndef DOXY_IGNORE_THIS
  struct Reserve
  {
Jan Möbius's avatar
Jan Möbius committed
325
    explicit Reserve(size_t _n) : n_(_n) {}
Jan Möbius's avatar
Jan Möbius committed
326 327 328 329 330 331
    void operator()(BaseProperty* _p) const { if (_p) _p->reserve(n_); }
    size_t n_;
  };

  struct Resize
  {
Jan Möbius's avatar
Jan Möbius committed
332
    explicit Resize(size_t _n) : n_(_n) {}
Jan Möbius's avatar
Jan Möbius committed
333 334 335 336
    void operator()(BaseProperty* _p) const { if (_p) _p->resize(n_); }
    size_t n_;
  };

Hans-Christian Ebke's avatar
Hans-Christian Ebke committed
337 338
  struct ResizeIfSmaller
  {
Jan Möbius's avatar
Jan Möbius committed
339
    explicit ResizeIfSmaller(size_t _n) : n_(_n) {}
Hans-Christian Ebke's avatar
Hans-Christian Ebke committed
340 341 342 343
    void operator()(BaseProperty* _p) const { if (_p && _p->n_elements() < n_) _p->resize(n_); }
    size_t n_;
  };

344 345 346 347 348 349
  struct ClearAll
  {
    ClearAll() {}
    void operator()(BaseProperty* _p) const { if (_p) _p->clear(); }
  };

Jan Möbius's avatar
Jan Möbius committed
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
  struct Swap
  {
    Swap(size_t _i0, size_t _i1) : i0_(_i0), i1_(_i1) {}
    void operator()(BaseProperty* _p) const { if (_p) _p->swap(i0_, i1_); }
    size_t i0_, i1_;
  };

  struct Delete
  {
    Delete() {}
    void operator()(BaseProperty* _p) const { if (_p) delete _p; _p=NULL; }
  };
#endif

  Properties   properties_;
};

}//namespace OpenMesh

#endif//OPENMESH_PROPERTYCONTAINER