IMP logo
IMP Reference Guide  2.19.0
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 <IMP/Vector.h>
18 
19 IMPKERNEL_BEGIN_NAMESPACE
20 
21 //! A typed index.
22 /** This can help disambiguate different integer based indexes floating
23  around to help avoid bugs caused by mixing them up. Care has been taken
24  so that it can be replaced by an integer everywhere, if needed. */
25 template <class Tag>
26 class Index : public Value {
27  int i_;
28 
29  friend class cereal::access;
30 
31  template<class Archive> void serialize(Archive &ar) {
32  ar(i_);
33  }
34 
35  public:
36  explicit Index(int i) : i_(i) {}
37  Index() : i_(-2) {}
38  int get_index() const {
39  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
40  IMP_INTERNAL_CHECK(i_ >= 0, "Invalid index");
41  return i_;
42  }
45  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
46  out << i_;
47  });
49  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
50  return i_;
51  });
52 };
53 template <class Tag>
54 inline unsigned int get_as_unsigned_int(Index<Tag> i) {
55  return i.get_index();
56 }
57 template <class Tag>
58 inline Index<Tag> get_invalid_index() {
59  return Index<Tag>(-1);
60 }
61 
62 // Compression types for serialization of IndexVector.
63 // Since these vectors are often sparse, we do basic compression on
64 // the serialized data. The data is written out in a number of blocks,
65 // each starting with one of these compression types, until we hit COMP_END.
66 namespace {
67  // No compression: this is followed by a size N and then N values
68  static const unsigned char COMP_NONE = 0;
69 
70  // Simple run-length encoding: followed by a size N and a single value
71  static const unsigned char COMP_RLE = 1;
72 
73  // More compression types can be added here...
74 
75  // End of serialization: we are done serializing this vector
76  static const unsigned char COMP_END = 100;
77 }
78 
79 //! Implements a vector tied to a particular index of type Index<Tag>.
80 template <class Tag, class T>
81 class IndexVector : public Vector<T> {
82  typedef Vector<T> P;
83 
84  friend class cereal::access;
85 
86  // No compression on output (use CompressedIndexVector for that)
87  template<class Archive> void save(Archive &ar) const {
88  size_t sz = P::size();
89  ar(sz);
90  // Write a single no-compression block. This allows us to add compression
91  // for this class in future without breaking the format.
92  ar(COMP_NONE); ar(sz);
93  auto it = P::begin();
94  while(sz-- > 0) {
95  ar(*it++);
96  }
97  ar(COMP_END);
98  }
99 
100  // Read both non-compressed and compressed serialized streams
101  template<class Archive> void load(Archive &ar) {
102  P::resize(0);
103  size_t sz;
104  ar(sz);
105  P::reserve(sz);
106  unsigned char comp_type;
107  ar(comp_type);
108  while(comp_type != COMP_END) {
109  if (comp_type == COMP_NONE) {
110  ar(sz);
111  while(sz-- > 0) {
112  T val;
113  ar(val);
114  P::push_back(val);
115  }
116  } else if (comp_type == COMP_RLE) {
117  ar(sz);
118  T val;
119  ar(val);
120  while(sz-- > 0) {
121  P::push_back(val);
122  }
123  } else {
124  IMP_THROW("Unsupported IndexVector compression type", ValueException);
125  }
126  ar(comp_type);
127  }
128  }
129 
130  public:
131  IndexVector(unsigned int sz, const T &t = T()) : P(sz, t) {}
132  IndexVector() {}
133  IMP_BRACKET(T, Index<Tag>, get_as_unsigned_int(i) < P::size(),
134  return P::operator[](get_as_unsigned_int(i)));
135 };
136 
137 // This class functions identically to IndexVector but compresses
138 // the data during serialization
139 template <class Tag, class T>
140 class CompressedIndexVector : public IndexVector<Tag, T> {
141  typedef Vector<T> P;
142 
143  template<class Archive> void write_no_compression(
144  Archive &ar, typename P::const_iterator start,
145  typename P::const_iterator end) const {
146  size_t sz = end - start;
147  ar(COMP_NONE); ar(sz);
148  while(start != end) {
149  ar(*start++);
150  }
151  }
152 
153  template<class Archive> void write_rle(
154  Archive &ar, typename P::const_iterator start,
155  typename P::const_iterator end) const {
156  size_t sz = end - start;
157  ar(COMP_RLE); ar(sz);
158  ar(*start);
159  }
160 
161  friend class cereal::access;
162  template<class Archive> void save(Archive &ar) const {
163  size_t sz = P::size();
164  ar(sz);
165  typename P::const_iterator pos = P::begin(), start = P::begin(), runend;
166  while (pos != P::end()) {
167  const T& val = *pos;
168  // update runend to point past the end of a run of same values,
169  // starting at pos
170  for (runend = pos + 1; runend != P::end() && *runend == val; ++runend) {}
171  // exclude very short runs
172  if (runend - pos > 10) {
173  if (pos > P::begin() && pos > start) {
174  // Write previous set of non-RLE values
175  write_no_compression(ar, start, pos);
176  }
177  write_rle(ar, pos, runend);
178  start = runend;
179  }
180  pos = runend;
181  }
182  if (start != P::end()) {
183  write_no_compression(ar, start, P::end());
184  }
185  ar(COMP_END);
186  }
187 };
188 
189 template <class Tag, class Container, class T>
190 void resize_to_fit(Container &v, Index<Tag> i, const T &default_value = T()) {
191  if (v.size() <= get_as_unsigned_int(i)) {
192  v.resize(get_as_unsigned_int(i) + 1, default_value);
193  }
194 }
195 
196 IMPKERNEL_END_NAMESPACE
197 
198 namespace cereal {
199  template <class Archive, class Tag, class T>
200  struct specialize<Archive, IMP::IndexVector<Tag, T>,
201  cereal::specialization::member_load_save> {};
202 }
203 
204 namespace cereal {
205  template <class Archive, class Tag, class T>
206  struct specialize<Archive, IMP::CompressedIndexVector<Tag, T>,
207  cereal::specialization::member_load_save> {};
208 }
209 
210 #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:26
#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:42
#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.
Base class for a simple primitive-like type.
Definition: Value.h:23
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:81
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
Macros to help with objects that can be printed to a stream.