IMP logo
IMP Reference Guide  2.20.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 <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 : public Value {
28  int i_;
29 
30  friend class cereal::access;
31 
32  template<class Archive> void serialize(Archive &ar) {
33  ar(i_);
34  }
35 
36  public:
37  explicit Index(int i) : i_(i) {}
38  Index() : i_(-2) {}
39  int get_index() const {
40  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
41  IMP_INTERNAL_CHECK(i_ >= 0, "Invalid index");
42  return i_;
43  }
46  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
47  out << i_;
48  });
50  IMP_INTERNAL_CHECK(i_ != -2, "Uninitialized index");
51  return i_;
52  });
53 };
54 template <class Tag>
55 inline unsigned int get_as_unsigned_int(Index<Tag> i) {
56  return i.get_index();
57 }
58 template <class Tag>
59 inline Index<Tag> get_invalid_index() {
60  return Index<Tag>(-1);
61 }
62 
63 // Compression types for serialization of IndexVector.
64 // Since these vectors are often sparse, we do basic compression on
65 // the serialized data. The data is written out in a number of blocks,
66 // each starting with one of these compression types, until we hit COMP_END.
67 namespace {
68  // No compression: this is followed by a size N and then N values
69  static const unsigned char COMP_NONE = 0;
70 
71  // Simple run-length encoding: followed by a size N and a single value
72  static const unsigned char COMP_RLE = 1;
73 
74  // More compression types can be added here...
75 
76  // End of serialization: we are done serializing this vector
77  static const unsigned char COMP_END = 100;
78 }
79 
80 //! Implements a vector tied to a particular index of type Index<Tag>.
81 /** When this class is serialized, the output data are compressed using simple
82  run-length encoding, as these vectors are often sparse. For objects that
83  do not implement operator== (e.g. VectorD, SphereD), a custom comparison
84  functor should be provided. */
85 template <class Tag, class T, class Equal = std::equal_to<T> >
86 class IndexVector : public Vector<T> {
87  typedef Vector<T> P;
88 
89  template<class Archive> void write_no_compression(
90  Archive &ar, typename P::const_iterator start,
91  typename P::const_iterator end) const {
92  size_t sz = end - start;
93  ar(COMP_NONE); ar(sz);
94  while(start != end) {
95  ar(*start++);
96  }
97  }
98 
99  template<class Archive> void write_rle(
100  Archive &ar, typename P::const_iterator start,
101  typename P::const_iterator end) const {
102  size_t sz = end - start;
103  ar(COMP_RLE); ar(sz);
104  ar(*start);
105  }
106 
107  friend class cereal::access;
108  template<class Archive> void save(Archive &ar) const {
109  size_t sz = P::size();
110  ar(sz);
111  typename P::const_iterator pos = P::begin(), start = P::begin(), runend;
112  Equal cmp;
113  while (pos != P::end()) {
114  const T& val = *pos;
115  // update runend to point past the end of a run of same values,
116  // starting at pos
117  for (runend = pos + 1; runend != P::end() && cmp(*runend, val);
118  ++runend) {}
119  // exclude very short runs
120  if (runend - pos > 10) {
121  if (pos > P::begin() && pos > start) {
122  // Write previous set of non-RLE values
123  write_no_compression(ar, start, pos);
124  }
125  write_rle(ar, pos, runend);
126  start = runend;
127  }
128  pos = runend;
129  }
130  if (start != P::end()) {
131  write_no_compression(ar, start, P::end());
132  }
133  ar(COMP_END);
134  }
135 
136  // Read both non-compressed and compressed serialized streams
137  template<class Archive> void load(Archive &ar) {
138  P::resize(0);
139  size_t sz;
140  ar(sz);
141  P::reserve(sz);
142  unsigned char comp_type;
143  ar(comp_type);
144  while(comp_type != COMP_END) {
145  if (comp_type == COMP_NONE) {
146  ar(sz);
147  while(sz-- > 0) {
148  T val;
149  ar(val);
150  P::push_back(val);
151  }
152  } else if (comp_type == COMP_RLE) {
153  ar(sz);
154  T val;
155  ar(val);
156  while(sz-- > 0) {
157  P::push_back(val);
158  }
159  } else {
160  IMP_THROW("Unsupported IndexVector compression type", ValueException);
161  }
162  ar(comp_type);
163  }
164  }
165 
166  public:
167  IndexVector(unsigned int sz, const T &t = T()) : P(sz, t) {}
168  IndexVector() {}
169  IMP_BRACKET(T, Index<Tag>, get_as_unsigned_int(i) < P::size(),
170  return P::operator[](get_as_unsigned_int(i)));
171 };
172 
173 template <class Tag, class Container, class T>
174 void resize_to_fit(Container &v, Index<Tag> i, const T &default_value = T()) {
175  if (v.size() <= get_as_unsigned_int(i)) {
176  v.resize(get_as_unsigned_int(i) + 1, default_value);
177  }
178 }
179 
180 IMPKERNEL_END_NAMESPACE
181 
182 namespace cereal {
183  template <class Archive, class Tag, class T>
184  struct specialize<Archive, IMP::IndexVector<Tag, T>,
185  cereal::specialization::member_load_save> {};
186 }
187 
188 #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: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:86
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.