IMP logo
IMP Reference Guide  develop.e004443c3b,2024/04/25
The Integrative Modeling Platform
Index.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Index.h
3  * \brief Utility types to refer to various types of indices
4  *
5  * Copyright 2007-2023 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_INDEX_H
10 #define IMPKERNEL_INDEX_H
11 
12 #include <IMP/kernel_config.h>
13 #include "bracket_macros.h"
14 #include "showable_macros.h"
15 #include "Value.h"
16 #include <cereal/access.hpp>
17 #include <functional>
18 #include <IMP/Vector.h>
19 
20 IMPKERNEL_BEGIN_NAMESPACE
21 
22 //! A typed index.
23 /** This can help disambiguate different integer based indexes floating
24  around to help avoid bugs caused by mixing them up. Care has been taken
25  so that it can be replaced by an integer everywhere, if needed. */
26 template <class Tag>
27 class Index {
28  // We should really derive from Value, but this seems to confuse gcc at least
29  // into padding the struct and wasting memory,
30  // e.g. sizeof(ParticleIndexPair) should be 8 (2*int) but is actually 12.
31  int i_;
32 
33  friend class cereal::access;
34 
35  template<class Archive> void serialize(Archive &ar) {
36  ar(i_);
37  }
38 
39  public:
40  explicit Index(int i) : i_(i) {}
41  Index() : i_(-2) {}
42  int get_index() const {
43  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
44  IMP_INTERNAL_CHECK(i_ >= 0, "Invalid index");
45  return i_;
46  }
49  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
50  out << i_;
51  });
53  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
54  return i_;
55  });
56 };
57 template <class Tag>
58 inline unsigned int get_as_unsigned_int(Index<Tag> i) {
59  return i.get_index();
60 }
61 template <class Tag>
62 inline Index<Tag> get_invalid_index() {
63  return Index<Tag>(-1);
64 }
65 
66 // Compression types for serialization of IndexVector.
67 // Since these vectors are often sparse, we do basic compression on
68 // the serialized data. The data is written out in a number of blocks,
69 // each starting with one of these compression types, until we hit COMP_END.
70 namespace {
71  // No compression: this is followed by a size N and then N values
72  static const unsigned char COMP_NONE = 0;
73 
74  // Simple run-length encoding: followed by a size N and a single value
75  static const unsigned char COMP_RLE = 1;
76 
77  // More compression types can be added here...
78 
79  // End of serialization: we are done serializing this vector
80  static const unsigned char COMP_END = 100;
81 }
82 
83 //! Implements a vector tied to a particular index of type Index<Tag>.
84 /** When this class is serialized, the output data are compressed using simple
85  run-length encoding, as these vectors are often sparse. For objects that
86  do not implement operator== (e.g. VectorD, SphereD), a custom comparison
87  functor should be provided. */
88 template <class Tag, class T, class Allocator = std::allocator<T>,
89  class Equal = std::equal_to<T> >
90 class IndexVector : public Vector<T, Allocator> {
91  typedef Vector<T, Allocator> P;
92 
93  template<class Archive> void write_no_compression(
94  Archive &ar, typename P::const_iterator start,
95  typename P::const_iterator end) const {
96  size_t sz = end - start;
97  ar(COMP_NONE); ar(sz);
98  while(start != end) {
99  ar(*start++);
100  }
101  }
102 
103  template<class Archive> void write_rle(
104  Archive &ar, typename P::const_iterator start,
105  typename P::const_iterator end) const {
106  size_t sz = end - start;
107  ar(COMP_RLE); ar(sz);
108  ar(*start);
109  }
110 
111  friend class cereal::access;
112  template<class Archive> void save(Archive &ar) const {
113  size_t sz = P::size();
114  ar(sz);
115  typename P::const_iterator pos = P::begin(), start = P::begin(), runend;
116  Equal cmp;
117  while (pos != P::end()) {
118  const T& val = *pos;
119  // update runend to point past the end of a run of same values,
120  // starting at pos
121  for (runend = pos + 1; runend != P::end() && cmp(*runend, val);
122  ++runend) {}
123  // exclude very short runs
124  if (runend - pos > 10) {
125  if (pos > P::begin() && pos > start) {
126  // Write previous set of non-RLE values
127  write_no_compression(ar, start, pos);
128  }
129  write_rle(ar, pos, runend);
130  start = runend;
131  }
132  pos = runend;
133  }
134  if (start != P::end()) {
135  write_no_compression(ar, start, P::end());
136  }
137  ar(COMP_END);
138  }
139 
140  // Read both non-compressed and compressed serialized streams
141  template<class Archive> void load(Archive &ar) {
142  P::resize(0);
143  size_t sz;
144  ar(sz);
145  P::reserve(sz);
146  unsigned char comp_type;
147  ar(comp_type);
148  while(comp_type != COMP_END) {
149  if (comp_type == COMP_NONE) {
150  ar(sz);
151  while(sz-- > 0) {
152  T val;
153  ar(val);
154  P::push_back(val);
155  }
156  } else if (comp_type == COMP_RLE) {
157  ar(sz);
158  T val;
159  ar(val);
160  while(sz-- > 0) {
161  P::push_back(val);
162  }
163  } else {
164  IMP_THROW("Unsupported IndexVector compression type", ValueException);
165  }
166  ar(comp_type);
167  }
168  }
169 
170  public:
171  IndexVector(unsigned int sz, const T &t = T()) : P(sz, t) {}
172  IndexVector() {}
173  IMP_BRACKET(T, Index<Tag>, get_as_unsigned_int(i) < P::size(),
174  return P::operator[](get_as_unsigned_int(i)));
175 };
176 
177 template <class Tag, class Container, class T>
178 void resize_to_fit(Container &v, Index<Tag> i, const T &default_value = T()) {
179  if (v.size() <= get_as_unsigned_int(i)) {
180  v.resize(get_as_unsigned_int(i) + 1, default_value);
181  }
182 }
183 
184 IMPKERNEL_END_NAMESPACE
185 
186 namespace cereal {
187  template <class Archive, class Tag, class T>
188  struct specialize<Archive, IMP::IndexVector<Tag, T>,
189  cereal::specialization::member_load_save> {};
190 }
191 
192 #endif /* IMPKERNEL_INDEX_H */
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
#define IMP_HASHABLE_INLINE(name, hashret)
Definition: hash_macros.h:18
A typed index.
Definition: Index.h:27
#define IMP_BRACKET(Value, Index, bounds_check_expr, expr)
Implement operator[] and at() for C++, and getitem for Python.
A more IMP-like version of the std::vector.
Definition: Vector.h:50
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown.
Definition: check_macros.h:139
Macros to handle array indexing.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
Implements a vector tied to a particular index of type Index<Tag>.
Definition: Index.h:90
A class for storing lists of IMP items.
#define IMP_THROW(message, exception_name)
Throw an exception with a message.
Definition: check_macros.h:50
Base class for a simple primitive-like type.
#define IMP_COMPARISONS_1(Name, field)
Implement comparison in a class using field as the variable to compare.
An exception for an invalid value being passed to IMP.
Definition: exception.h:136
Abstract class for containers of particles.
Macros to help with objects that can be printed to a stream.