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

#ifndef OPENMESH_PROPERTYCONTAINER
#define OPENMESH_PROPERTYCONTAINER

#include <OpenMesh/Core/Utils/Property.hh>
48
#include <OpenMesh/Core/Utils/TypeName.hh>
Jan Möbius's avatar
Jan Möbius committed
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

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

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

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

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


  //------------------------------------------------------------- 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)
  {
82 83
    // 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
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    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;
Jan Möbius's avatar
Jan Möbius committed
101 102
    for ( ; p_it!=p_end && *p_it!=nullptr; ++p_it, ++idx ) {};
    if (p_it==p_end) properties_.push_back(nullptr);
103
    properties_[idx] = new PropertyT<T>(_name, get_type_name<T>() );        // create a new property with requested name and given (system dependent) internal typename
Jan Möbius's avatar
Jan Möbius committed
104 105 106 107 108 109 110 111 112 113
    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)
    {
Jan Möbius's avatar
Jan Möbius committed
114
      if (*p_it != nullptr &&
Jan Möbius's avatar
Jan Möbius committed
115
         (*p_it)->name() == _name  //skip deleted properties
116
         && (*p_it)->internal_type_name() == get_type_name<T>()     // new check type
Jan Möbius's avatar
Jan Möbius committed
117 118 119 120 121 122 123 124 125 126 127 128 129
         )
      {
        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)
    {
Jan Möbius's avatar
Jan Möbius committed
130
      if (*p_it != nullptr && (*p_it)->name() == _name) //skip deleted properties
Jan Möbius's avatar
Jan Möbius committed
131 132 133 134
      {
        return *p_it;
      }
    }
Jan Möbius's avatar
Jan Möbius committed
135
    return nullptr;
Jan Möbius's avatar
Jan Möbius committed
136 137 138 139 140
  }

  template <class T> PropertyT<T>& property(BasePropHandleT<T> _h)
  {
    assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size());
Jan Möbius's avatar
Jan Möbius committed
141
    assert(properties_[_h.idx()] != nullptr);
142 143
    assert( properties_[_h.idx()]->internal_type_name() == get_type_name<T>() );
    PropertyT<T> *p = static_cast< PropertyT<T>* > (properties_[_h.idx()]);
Jan Möbius's avatar
Jan Möbius committed
144
    assert(p != nullptr);
Jan Möbius's avatar
Jan Möbius committed
145 146 147 148 149 150 151
    return *p;
  }


  template <class T> const PropertyT<T>& property(BasePropHandleT<T> _h) const
  {
    assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size());
Jan Möbius's avatar
Jan Möbius committed
152
    assert(properties_[_h.idx()] != nullptr);
153 154
    assert( properties_[_h.idx()]->internal_type_name() == get_type_name<T>() );
    PropertyT<T> *p = static_cast< PropertyT<T>* > (properties_[_h.idx()]);
Jan Möbius's avatar
Jan Möbius committed
155
    assert(p != nullptr);
Jan Möbius's avatar
Jan Möbius committed
156 157 158 159 160 161 162 163
    return *p;
  }


  template <class T> void remove(BasePropHandleT<T> _h)
  {
    assert(_h.idx() >= 0 && _h.idx() < (int)properties_.size());
    delete properties_[_h.idx()];
Jan Möbius's avatar
Jan Möbius committed
164
    properties_[_h.idx()] = nullptr;
Jan Möbius's avatar
Jan Möbius committed
165 166 167 168 169
  }


  void clear()
  {
170 171 172 173 174 175 176 177 178 179
	// 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
180 181 182 183 184
  }


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

185 186 187 188
/*
 * In C++11 an beyond we can introduce more efficient and more legible
 * implementations of the following methods.
 */
189
#if ((defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(OPENMESH_VECTOR_LEGACY)
190 191 192
  /**
   * Reserves space for \p _n elements in all property vectors.
   */
193 194 195 196 197
  void reserve(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(),
            [_n](BaseProperty* p) { if (p) p->reserve(_n); });
  }

198 199 200
  /**
   * Resizes all property vectors to the specified size.
   */
201 202 203 204 205
  void resize(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(),
            [_n](BaseProperty* p) { if (p) p->resize(_n); });
  }

206 207 208 209 210 211 212 213
  /**
   * 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
214 215 216 217 218
  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); });
  }

219 220 221 222
  /**
   * Swaps the items with index \p _i0 and index \p _i1 in all property
   * vectors.
   */
223 224 225 226 227
  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
228 229 230
  /**
   * Reserves space for \p _n elements in all property vectors.
   */
Jan Möbius's avatar
Jan Möbius committed
231 232 233 234
  void reserve(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(), Reserve(_n));
  }

235 236 237
  /**
   * Resizes all property vectors to the specified size.
   */
Jan Möbius's avatar
Jan Möbius committed
238 239 240 241
  void resize(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(), Resize(_n));
  }

242 243 244 245 246 247 248 249
  /**
   * 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
250 251 252 253
  void resize_if_smaller(size_t _n) const {
    std::for_each(properties_.begin(), properties_.end(), ResizeIfSmaller(_n));
  }

254 255 256 257
  /**
   * Swaps the items with index \p _i0 and index \p _i1 in all property
   * vectors.
   */
Jan Möbius's avatar
Jan Möbius committed
258 259 260
  void swap(size_t _i0, size_t _i1) const {
    std::for_each(properties_.begin(), properties_.end(), Swap(_i0, _i1));
  }
261
#endif
Jan Möbius's avatar
Jan Möbius committed
262 263 264 265 266 267 268 269 270



protected: // generic add/get

  size_t _add( BaseProperty* _bp )
  {
    Properties::iterator p_it=properties_.begin(), p_end=properties_.end();
    size_t idx=0;
Jan Möbius's avatar
Jan Möbius committed
271 272
    for (; p_it!=p_end && *p_it!=nullptr; ++p_it, ++idx) {};
    if (p_it==p_end) properties_.push_back(nullptr);
Jan Möbius's avatar
Jan Möbius committed
273 274 275 276 277 278 279
    properties_[idx] = _bp;
    return idx;
  }

  BaseProperty& _property( size_t _idx )
  {
    assert( _idx < properties_.size());
Jan Möbius's avatar
Jan Möbius committed
280
    assert( properties_[_idx] != nullptr);
Jan Möbius's avatar
Jan Möbius committed
281
    BaseProperty *p = properties_[_idx];
Jan Möbius's avatar
Jan Möbius committed
282
    assert( p != nullptr );
Jan Möbius's avatar
Jan Möbius committed
283 284 285 286 287 288
    return *p;
  }

  const BaseProperty& _property( size_t _idx ) const
  {
    assert( _idx < properties_.size());
Jan Möbius's avatar
Jan Möbius committed
289
    assert( properties_[_idx] != nullptr);
Jan Möbius's avatar
Jan Möbius committed
290
    BaseProperty *p = properties_[_idx];
Jan Möbius's avatar
Jan Möbius committed
291
    assert( p != nullptr );
Jan Möbius's avatar
Jan Möbius committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    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
312
    explicit Reserve(size_t _n) : n_(_n) {}
Jan Möbius's avatar
Jan Möbius committed
313 314 315 316 317 318
    void operator()(BaseProperty* _p) const { if (_p) _p->reserve(n_); }
    size_t n_;
  };

  struct Resize
  {
Jan Möbius's avatar
Jan Möbius committed
319
    explicit Resize(size_t _n) : n_(_n) {}
Jan Möbius's avatar
Jan Möbius committed
320 321 322 323
    void operator()(BaseProperty* _p) const { if (_p) _p->resize(n_); }
    size_t n_;
  };

Hans-Christian Ebke's avatar
Hans-Christian Ebke committed
324 325
  struct ResizeIfSmaller
  {
Jan Möbius's avatar
Jan Möbius committed
326
    explicit ResizeIfSmaller(size_t _n) : n_(_n) {}
Hans-Christian Ebke's avatar
Hans-Christian Ebke committed
327 328 329 330
    void operator()(BaseProperty* _p) const { if (_p && _p->n_elements() < n_) _p->resize(n_); }
    size_t n_;
  };

331 332 333 334 335 336
  struct ClearAll
  {
    ClearAll() {}
    void operator()(BaseProperty* _p) const { if (_p) _p->clear(); }
  };

Jan Möbius's avatar
Jan Möbius committed
337 338 339 340 341 342 343 344 345 346
  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() {}
347
    void operator()(BaseProperty* _p) const { if (_p) delete _p; }
Jan Möbius's avatar
Jan Möbius committed
348 349 350 351 352 353 354 355 356 357
  };
#endif

  Properties   properties_;
};

}//namespace OpenMesh

#endif//OPENMESH_PROPERTYCONTAINER