first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / structures / roller.h
1 #ifndef ROLLER_CLASS
2 #define ROLLER_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : roller                                                            *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 1996-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include <basis/definitions.h>
19
20 namespace structures {
21
22 //! Maintains a pseudo-unique identifier number and issues a new one on demand.
23 /*!
24   The unique id is templated on the type of identifier, but the type used must
25   support:
26     1) assigment to a value,
27     2) a greater than or equal operator (>=), and
28     3) the increment operator (++).
29   Zero is often treated as the invalid / empty / inactive identifier, but
30   roller does not prevent its use since some ranges might need to bridge
31   between negative and positive numbers.
32 */
33
34 template <class contents>
35 class roller
36 {
37 public:
38   roller(contents start_of_range, contents end_of_range);
39     //!< constructs a roller between the start and end ranges.
40     /*!< this constructs a roller that runs from the value "start_of_range"
41     and will stay smaller than "end_of_range" (unless the initial parameters
42     are screwed up; this class doesn't validate the start and end of range).
43     when the roller hits the end of range, then its value is reset to the
44     "start_of_range" again. */
45
46   ~roller();
47
48   // these report the constructor parameters.
49   contents minimum() { return _start_of_range; }
50     //!< the smallest value that the roller can have.
51   contents maximum() { return _end_of_range; }
52     //!< the outer limit of the roller; it should never reach this.
53
54   contents next_id();
55     //!< returns a unique (per instance of this type) id.
56
57   contents current() const;
58     //!< returns the current id to be used; be careful!
59     /*!< this value will be the next one returned, so only look at the current
60     id and don't use it unwisely.  this function is useful if you want to
61     assign an id provisionally but might not want to complete the issuance of
62     it. */
63
64   void set_current(contents new_current);
65     //!< allows the current id to be manipulated.
66     /*!< this must be done with care lest existing ids be re-used. */
67
68 private:
69   contents _current_id;  //!< the next id to bring forth.
70   contents _start_of_range;  //!< first possible value.
71   contents _end_of_range;  //!< one more than last possible value.
72 };
73
74 //////////////
75
76 //! A roller that's based on integers.  This is the most common type so far.
77
78 class int_roller : public roller<int>
79 {
80 public:
81   int_roller(int start_of_range, int end_of_range)
82           : roller<int>(start_of_range, end_of_range) {}
83 };
84
85 //////////////
86
87 // implementations below...
88
89 template <class contents>
90 roller<contents>::roller(contents start, contents end)
91 : _current_id(start), _start_of_range(start), _end_of_range(end) {}
92
93 template <class contents>
94 void roller<contents>::set_current(contents new_current)
95 {
96   _current_id = new_current;
97   if (_current_id >= _end_of_range) _current_id = _start_of_range;
98 }
99
100 template <class contents> roller<contents>::~roller() {}
101
102 template <class contents> contents roller<contents>::current() const
103 { return _current_id; }
104
105 template <class contents> contents roller<contents>::next_id()
106 {
107   contents to_return = _current_id;
108   if (to_return == _end_of_range) {
109     // somehow the id to return is at the end of the range.  this probably
110     // means the end of range condition wasn't detected last time due to an
111     // error in the parameters or the operation of == or ++ in the templated
112     // class.
113     _current_id = _start_of_range;
114     to_return = _current_id;
115   }
116   _current_id++;  // next id.
117   if (_current_id == _end_of_range) _current_id = _start_of_range;
118     // reset the current position when hits the end of the range.
119   return to_return;
120 }
121
122 } //namespace.
123
124 #endif
125