1 // Copyright (c) 2014-2020 Thomas Fussell
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE
20 //
21 // @license: http://www.opensource.org/licenses/mit-license.php
22 // @author: see AUTHORS file
23 
24 #pragma once
25 
26 #include <algorithm>
27 #include <cstdint>
28 #include <string>
29 
30 #include <xlnt/xlnt_config.hpp>
31 
32 // We might want to change these types for various optimizations in the future
33 // so use typedefs.
34 
35 namespace xlnt {
36 
37 /// <summary>
38 /// All rows should be referred to by an instance of this type.
39 /// </summary>
40 using row_t = std::uint32_t;
41 
42 /// <summary>
43 /// Columns can be referred to as a string A,B,...Z,AA,AB,..,ZZ,AAA,...,ZZZ
44 /// or as a 1-indexed index. This class encapsulates both of these forms of
45 /// column referencing and allows for conversions between them.
46 /// </summary>
47 class XLNT_API column_t
48 {
49 public:
50     /// <summary>
51     /// Alias declaration for the internal numeric type of this column.
52     /// </summary>
53     using index_t = std::uint32_t;
54 
55     /// <summary>
56     /// Convert a column letter into a column number (e.g. B -> 2)
57     /// </summary>
58     /// <remarks>
59     /// Excel only supports 1 - 3 letter column names from A->ZZZ, so we
60     /// restrict our column names to 1 - 3 characters, each in the range A - Z.
61     /// Strings outside this range and malformed strings will throw column_string_index_exception.
62     /// </remarks>
63     static index_t column_index_from_string(const std::string &column_string);
64 
65     /// <summary>
66     /// Convert a column number into a column letter (3 -> 'C')
67     /// </summary>
68     /// <remarks>
69     /// Right shift the column, column_index, by 26 to find column letters in reverse
70     /// order. These indices are 1-based, and can be converted to ASCII
71     /// ordinals by adding 64.
72     /// </remarks>
73     static std::string column_string_from_index(index_t column_index);
74 
75     /// <summary>
76     /// Default constructor. The column points to the "A" column.
77     /// </summary>
78     column_t();
79 
80     /// <summary>
81     /// Constructs a column from a number.
82     /// </summary>
83     column_t(index_t column_index);
84 
85     /// <summary>
86     /// Constructs a column from a string.
87     /// </summary>
88     column_t(const std::string &column_string);
89 
90     /// <summary>
91     /// Constructs a column from a string.
92     /// </summary>
93     column_t(const char *column_string);
94 
95     /// <summary>
96     /// Returns a string representation of this column index.
97     /// </summary>
98     std::string column_string() const;
99 
100     /// <summary>
101     /// Sets this column to be equal to rhs and return reference to self.
102     /// </summary>
103     column_t &operator=(const std::string &rhs);
104 
105     /// <summary>
106     /// Sets this column to be equal to rhs and return reference to self.
107     /// </summary>
108     column_t &operator=(const char *rhs);
109 
110     /// <summary>
111     /// Returns true if this column refers to the same column as other.
112     /// </summary>
113     bool operator==(const column_t &other) const;
114 
115     /// <summary>
116     /// Returns true if this column doesn't refer to the same column as other.
117     /// </summary>
118     bool operator!=(const column_t &other) const;
119 
120     /// <summary>
121     /// Returns true if this column refers to the same column as other.
122     /// </summary>
123     bool operator==(int other) const;
124 
125     /// <summary>
126     /// Returns true if this column refers to the same column as other.
127     /// </summary>
128     bool operator==(index_t other) const;
129 
130     /// <summary>
131     /// Returns true if this column refers to the same column as other.
132     /// </summary>
133     bool operator==(const std::string &other) const;
134 
135     /// <summary>
136     /// Returns true if this column refers to the same column as other.
137     /// </summary>
138     bool operator==(const char *other) const;
139 
140     /// <summary>
141     /// Returns true if this column doesn't refer to the same column as other.
142     /// </summary>
143     bool operator!=(int other) const;
144 
145     /// <summary>
146     /// Returns true if this column doesn't refer to the same column as other.
147     /// </summary>
148     bool operator!=(index_t other) const;
149 
150     /// <summary>
151     /// Returns true if this column doesn't refer to the same column as other.
152     /// </summary>
153     bool operator!=(const std::string &other) const;
154 
155     /// <summary>
156     /// Returns true if this column doesn't refer to the same column as other.
157     /// </summary>
158     bool operator!=(const char *other) const;
159 
160     /// <summary>
161     /// Returns true if other is to the right of this column.
162     /// </summary>
163     bool operator>(const column_t &other) const;
164 
165     /// <summary>
166     /// Returns true if other is to the right of or equal to this column.
167     /// </summary>
168     bool operator>=(const column_t &other) const;
169 
170     /// <summary>
171     /// Returns true if other is to the left of this column.
172     /// </summary>
173     bool operator<(const column_t &other) const;
174 
175     /// <summary>
176     /// Returns true if other is to the left of or equal to this column.
177     /// </summary>
178     bool operator<=(const column_t &other) const;
179 
180     /// <summary>
181     /// Returns true if other is to the right of this column.
182     /// </summary>
183     bool operator>(const column_t::index_t &other) const;
184 
185     /// <summary>
186     /// Returns true if other is to the right of or equal to this column.
187     /// </summary>
188     bool operator>=(const column_t::index_t &other) const;
189 
190     /// <summary>
191     /// Returns true if other is to the left of this column.
192     /// </summary>
193     bool operator<(const column_t::index_t &other) const;
194 
195     /// <summary>
196     /// Returns true if other is to the left of or equal to this column.
197     /// </summary>
198     bool operator<=(const column_t::index_t &other) const;
199 
200     /// <summary>
201     /// Pre-increments this column, making it point to the column one to the right and returning a reference to it.
202     /// </summary>
203     column_t &operator++();
204 
205     /// <summary>
206     /// Pre-deccrements this column, making it point to the column one to the left and returning a reference to it.
207     /// </summary>
208     column_t &operator--();
209 
210     /// <summary>
211     /// Post-increments this column, making it point to the column one to the right and returning the old column.
212     /// </summary>
213     column_t operator++(int);
214 
215     /// <summary>
216     /// Post-decrements this column, making it point to the column one to the left and returning the old column.
217     /// </summary>
218     column_t operator--(int);
219 
220     /// <summary>
221     /// Returns the result of adding rhs to this column.
222     /// </summary>
223     friend XLNT_API column_t operator+(column_t lhs, const column_t &rhs);
224 
225     /// <summary>
226     /// Returns the result of subtracing lhs by rhs column.
227     /// </summary>
228     friend XLNT_API column_t operator-(column_t lhs, const column_t &rhs);
229 
230     /// <summary>
231     /// Adds rhs to this column and returns a reference to this column.
232     /// </summary>
233     column_t &operator+=(const column_t &rhs);
234 
235     /// <summary>
236     /// Subtracts rhs from this column and returns a reference to this column.
237     /// </summary>
238     column_t &operator-=(const column_t &rhs);
239 
240     /// <summary>
241     /// Returns true if other is to the right of this column.
242     /// </summary>
243     friend XLNT_API bool operator>(const column_t::index_t &left, const column_t &right);
244 
245     /// <summary>
246     /// Returns true if other is to the right of or equal to this column.
247     /// </summary>
248     friend XLNT_API bool operator>=(const column_t::index_t &left, const column_t &right);
249 
250     /// <summary>
251     /// Returns true if other is to the left of this column.
252     /// </summary>
253     friend XLNT_API bool operator<(const column_t::index_t &left, const column_t &right);
254 
255     /// <summary>
256     /// Returns true if other is to the left of or equal to this column.
257     /// </summary>
258     friend XLNT_API bool operator<=(const column_t::index_t &left, const column_t &right);
259 
260     /// <summary>
261     /// Swaps the columns that left and right refer to.
262     /// </summary>
263     friend XLNT_API void swap(column_t &left, column_t &right);
264 
265     /// <summary>
266     /// Internal numeric value of this column index.
267     /// </summary>
268     index_t index;
269 };
270 
271 enum class row_or_col_t : int
272 {
273     row,
274     column
275 };
276 
277 /// <summary>
278 /// Functor for hashing a column.
279 /// Allows for use of std::unordered_set<column_t, column_hash> and similar.
280 /// </summary>
281 struct XLNT_API column_hash
282 {
283     /// <summary>
284     /// Returns the result of hashing column k.
285     /// </summary>
286     std::size_t operator()(const column_t &k) const;
287 };
288 
289 } // namespace xlnt
290 
291 namespace std {
292 
293 /// <summary>
294 /// Template specialization to allow xlnt::column_t to be used as a key in a std container.
295 /// </summary>
296 template <>
297 struct hash<xlnt::column_t>
298 {
299     /// <summary>
300     /// Returns the result of hashing column k.
301     /// </summary>
operator ()std::hash302     size_t operator()(const xlnt::column_t &k) const
303     {
304         static xlnt::column_hash hasher;
305         return hasher(k);
306     }
307 };
308 
309 } // namespace std
310