IMP logo
IMP Reference Guide  2.21.0
The Integrative Modeling Platform
Array.h
Go to the documentation of this file.
1 /**
2  * \file IMP/Array.h
3  * \brief Classes to handle static sized arrays of things.
4  *
5  * Copyright 2007-2024 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_ARRAY_H
10 #define IMPKERNEL_ARRAY_H
11 
12 #include <IMP/kernel_config.h>
13 #include "Value.h"
14 #include "comparison_macros.h"
15 #include "hash_macros.h"
16 #include "check_macros.h"
17 #include "showable_macros.h"
18 #include <array>
19 #include <type_traits>
20 #include <cereal/access.hpp>
21 #include <cereal/types/array.hpp>
22 
23 IMPKERNEL_BEGIN_NAMESPACE
24 
25 //! A class to store a fixed array of same-typed values.
26 /** Only the constructor with the correct number of arguments for the
27  dimensionality can be used.
28 
29  Elements can be accessed using [] notation or std::get. The latter
30  is more efficient when the index is a constant, since the bounds check
31  can be done at compile time rather than runtime, e.g. x = std::get<0>(array)
32  is more efficient than x = array[0].
33 
34  \note These are mapped to/from Python tuples, so there is
35  no need to use types that are typedefs of this on the Python side.
36 
37  \see ConstVector
38  */
39 template <unsigned int D, class Data, class SwigData = Data>
40 class Array : public Value {
41  typedef std::array<Data, D> Storage;
42  Storage d_;
43 
44  friend class cereal::access;
45  template<class Archive> void serialize(Archive &ar) {
46  ar(d_);
47  }
48 
49  int compare(const Array<D, Data, SwigData>& o) const {
50  for (unsigned int i = 0; i < D; ++i) {
51  if (d_[i] < o.get(i))
52  return -1;
53  else if (d_[i] > o.get(i))
54  return 1;
55  }
56  return 0;
57  }
58 
59  public:
60 #ifndef IMP_DOXYGEN
61  typedef SwigData value_type;
62 #endif
63  unsigned int get_dimension() {
64  return D;
65  };
66  Array() {}
67 
68  template<int DT=D, typename std::enable_if<DT == 2>::type* = nullptr>
69  Array(SwigData x, SwigData y) {
70  d_[0] = x;
71  d_[1] = y;
72  }
73 
74  template<int DT=D, typename std::enable_if<DT == 3>::type* = nullptr>
75  Array(SwigData x, SwigData y, SwigData z) {
76  d_[0] = x;
77  d_[1] = y;
78  d_[2] = z;
79  }
80 
81  template<int DT=D, typename std::enable_if<DT == 4>::type* = nullptr>
82  Array(SwigData x0, SwigData x1, SwigData x2, SwigData x3) {
83  d_[0] = x0;
84  d_[1] = x1;
85  d_[2] = x2;
86  d_[3] = x3;
87  }
88 
89  SwigData get(unsigned int i) const { return d_[i]; }
90 
91  IMP_HASHABLE_INLINE(Array, std::size_t seed = 0;
92  for (unsigned int i = 0; i < D; ++i) {
93  boost::hash_combine(seed, d_[i]);
94  } return seed;);
96 #ifndef SWIG
97  const Data operator[](unsigned int i) const {
98  IMP_USAGE_CHECK(i < D, "Out of range");
99  return d_[i];
100  }
101  Data& operator[](unsigned int i) {
102  IMP_USAGE_CHECK(i < D, "Out of range");
103  return d_[i];
104  }
105 #ifndef IMP_DOXYGEN
106  void set_item(unsigned int i, SwigData v) const {
107  IMP_USAGE_CHECK(i < D, "Out of range");
108  d_[i] = v;
109  }
110 #endif
111 #endif
112 #ifndef IMP_DOXYGEN
113  SwigData __getitem__(unsigned int i) const {
114  if (i >= D) IMP_THROW("Out of bound " << i << " vs " << D, IndexException);
115  return operator[](i);
116  }
117  unsigned int __len__() const { return D; }
118 #endif
119 #ifndef SWIG
120  unsigned int size() const { return D; }
121 #endif
122  std::string get_name() const {
123  std::ostringstream oss;
124  oss << "\"";
125  for (unsigned int i = 0; i < D; ++i) {
126  if (i > 0) {
127  oss << "\" and \"";
128  }
129  oss << d_[i];
130  }
131  oss << "\"";
132  return oss.str();
133  }
134  IMP_SHOWABLE_INLINE(Array, { out << get_name(); });
135  typedef typename Storage::iterator iterator;
136  iterator begin() { return d_.begin(); }
137  iterator end() { return d_.end(); }
138  typedef typename Storage::const_iterator const_iterator;
139  const_iterator begin() const { return d_.begin(); }
140  const_iterator end() const { return d_.end(); }
141 
142  Data* data() {
143  if (d_.empty()) {
144  return NULL;
145  } else {
146  return &d_.front();
147  }
148  }
149 
150  const Data* data() const {
151  if (d_.empty()) {
152  return NULL;
153  } else {
154  return &d_.front();
155  }
156  }
157 };
158 
159 #if !defined(IMP_DOXYGEN) && !defined(SWIG)
160 template <unsigned int D, class Data, class SwigData>
161 inline std::size_t hash_value(const Array<D, Data, SwigData> &t) {
162  return t.__hash__();
163 }
164 #endif
165 
166 IMPKERNEL_END_NAMESPACE
167 
168 /* Overload std::get to work on IMP::Array similarly to std::array */
169 namespace std {
170  template <unsigned int I, unsigned int D, class Data, class SwigData>
171  const Data& get(const IMP::Array<D, Data, SwigData> &arr) {
172  static_assert(I < D, "array index is within bounds");
173  return *(arr.begin() + I);
174  }
175 
176  template <unsigned int I, unsigned int D, class Data, class SwigData>
177  Data& get(IMP::Array<D, Data, SwigData> &arr) {
178  static_assert(I < D, "array index is within bounds");
179  return *(arr.begin() + I);
180  }
181 }
182 
183 #endif /* IMPKERNEL_ARRAY_H */
#define IMP_SHOWABLE_INLINE(Name, how_to_show)
Declare the methods needed by an object that can be printed.
Helper macros for implementing comparisons of IMP objects.
A class to store a fixed array of same-typed values.
Definition: Array.h:40
#define IMP_HASHABLE_INLINE(name, hashret)
Definition: hash_macros.h:18
#define IMP_COMPARISONS(Name)
Implement comparison in a class using a compare function.
Base class for a simple primitive-like type.
Definition: Value.h:23
int compare(const VectorD< D > &a, const VectorD< D > &b)
lexicographic comparison of two vectors
Definition: VectorD.h:166
Helper macros for implementing hashable classes.
An exception for a request for an invalid member of a container.
Definition: exception.h:156
#define IMP_THROW(message, exception_name)
Throw an exception with a message.
Definition: check_macros.h:50
Helper macros for throwing and handling exceptions.
Base class for a simple primitive-like type.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
Macros to help with objects that can be printed to a stream.