created template class for tracking lists in directories, converted priority module to use this class
Stefan Schuermans

Stefan Schuermans commited on 2011-12-10 22:52:36
Showing 5 changed files, with 284 additions and 110 deletions.

... ...
@@ -0,0 +1,84 @@
1
+/* Blinker
2
+   Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef LISTTRACKER_H
7
+#define LISTTRACKER_H
8
+
9
+#include <list>
10
+#include <string>
11
+
12
+#include "Directory.h"
13
+#include "File.h"
14
+
15
+namespace Blinker {
16
+
17
+/**
18
+ * @brief tracker of a list kept in a directory
19
+ * @param[in] PARENT type of parent object
20
+ * @param[in] TYPE type of objects to allocate for list entries
21
+ * @param[in] FIDI if to track files or subdirs in directory
22
+                   (File or Directory)
23
+ */
24
+template<typename PARENT, typename TYPE, typename FIDI>
25
+class ListTracker
26
+{
27
+public:
28
+  /// list entry
29
+  struct Entry {
30
+    std::string m_name;  ///< name of list entry
31
+    TYPE        *m_pObj; ///< object
32
+  };
33
+
34
+  /// list
35
+  typedef std::list<Entry> List;
36
+
37
+  /// list iterator
38
+  typedef typename List::const_reverse_iterator ListIt;
39
+
40
+public:
41
+  /**
42
+   * @brief constructor
43
+   * @param[in] parent parent object
44
+   * @param[in] dir directory containing list and begin tracked
45
+   */
46
+  ListTracker(PARENT &parent, const Directory &dir);
47
+
48
+  /// destructor
49
+  virtual ~ListTracker();
50
+
51
+private:
52
+  /// copy constructor disabled
53
+  ListTracker(const ListTracker &that);
54
+
55
+  /// assignment operator disabled
56
+  const ListTracker & operator=(const ListTracker &that);
57
+
58
+public:
59
+  /// initialize list by reading directory
60
+  void init();
61
+
62
+  /// clear list
63
+  void clear();
64
+
65
+  /// check for update of configuration
66
+  void updateConfig();
67
+
68
+protected:
69
+  /// light update of list, i.e. check all entries in current list
70
+  void updateListLight();
71
+
72
+  /// full update of list, i.e. scan files/subdirs in list directory
73
+  void updateListFull();
74
+
75
+public:
76
+  PARENT    &m_parent; ///< parent object
77
+  Directory m_dir;     ///< directory containing list and being tracked
78
+  List      m_list;    ///< list begin tracked
79
+}; // class ListTracker
80
+
81
+} // namespace Blinker
82
+
83
+#endif // #ifndef LISTTRACKER_H
84
+
... ...
@@ -0,0 +1,177 @@
1
+/* Blinker
2
+   Copyright 2011 Stefan Schuermans <stefan@blinkenarea.org>
3
+   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4
+   a blinkenarea.org project */
5
+
6
+#ifndef LISTTRACKER_IMPL_H
7
+#define LISTTRACKER_IMPL_H
8
+
9
+#include <list>
10
+#include <string>
11
+
12
+#include "Directory.h"
13
+#include "File.h"
14
+#include "ListTracker.h"
15
+
16
+namespace Blinker {
17
+
18
+/* ###################
19
+   # ListTrackerFiDi #
20
+   ################### */
21
+
22
+
23
+/// internal helper class to achive different behavior for FIDI parameter
24
+template <typename FIDI>
25
+class ListTrackerFiDi
26
+{
27
+public:
28
+  static inline Directory::Type type();
29
+  static inline FIDI get(const Directory &dir, const std::string name);
30
+};
31
+
32
+template<>
33
+inline Directory::Type ListTrackerFiDi<File>::type()
34
+{
35
+  return Directory::TypeFile;
36
+}
37
+
38
+template<>
39
+inline File ListTrackerFiDi<File>::
40
+  get(const Directory &dir, const std::string name)
41
+{
42
+  return dir.getFile(name);
43
+}
44
+
45
+template<>
46
+inline Directory::Type ListTrackerFiDi<Directory>::type()
47
+{
48
+  return Directory::TypeSubdir;
49
+}
50
+
51
+template<>
52
+inline Directory ListTrackerFiDi<Directory>::
53
+  get(const Directory &dir, const std::string name)
54
+{
55
+  return dir.getSubdir(name);
56
+}
57
+
58
+/* ###############
59
+   # ListTracker #
60
+   ############### */
61
+
62
+/**
63
+ * @brief constructor
64
+ * @param[in] dir directory containing list and begin tracked
65
+ * @param[in] parent parent object
66
+ */
67
+template<typename PARENT, typename TYPE, typename FIDI>
68
+ListTracker<PARENT, TYPE, FIDI>::ListTracker(PARENT &parent,
69
+                                             const Directory &dir):
70
+  m_parent(parent),
71
+  m_dir(dir)
72
+{
73
+}
74
+
75
+/// destructor
76
+template<typename PARENT, typename TYPE, typename FIDI>
77
+ListTracker<PARENT, TYPE, FIDI>::~ListTracker()
78
+{
79
+  /* free leftover list entries:
80
+     Depending on the interaction bet ween the list entry object and
81
+     the parent, it might be too late to free them, as the parent might
82
+     already be partly deconstructed and thus might be in an inconsistent
83
+     state. It's recommended to call clear manually before, so that the
84
+     following call becomes a no-operation. */
85
+  clear();
86
+}
87
+
88
+/// initialize list by reading directory
89
+template<typename PARENT, typename TYPE, typename FIDI>
90
+void ListTracker<PARENT, TYPE, FIDI>::init()
91
+{
92
+  updateListFull();
93
+}
94
+
95
+/// clear list
96
+template<typename PARENT, typename TYPE, typename FIDI>
97
+void ListTracker<PARENT, TYPE, FIDI>::clear()
98
+{
99
+  while (!m_list.empty()) {
100
+    delete m_list.back().m_pObj;
101
+    m_list.pop_back();
102
+  }
103
+}
104
+
105
+/// check for update of configuration
106
+template<typename PARENT, typename TYPE, typename FIDI>
107
+void ListTracker<PARENT, TYPE, FIDI>::updateConfig()
108
+{
109
+  // directory modified -> full, otherwise -> light
110
+  if (m_dir.checkModified())
111
+    updateListFull();
112
+  else
113
+    updateListLight();
114
+}
115
+
116
+/// light update of list, i.e. check all entries in current list
117
+template<typename PARENT, typename TYPE, typename FIDI>
118
+void ListTracker<PARENT, TYPE, FIDI>::updateListLight()
119
+{
120
+  typename List::iterator it;
121
+  for (it = m_list.begin(); it != m_list.end(); ++it)
122
+    it->m_pObj->updateConfig();
123
+}
124
+
125
+/// full update of list, i.e. scan files/subdirs in list directory
126
+template<typename PARENT, typename TYPE, typename FIDI>
127
+void ListTracker<PARENT, TYPE, FIDI>::updateListFull()
128
+{
129
+  // get list of files/subdirs in directory
130
+  typedef std::list<std::string> FileList;
131
+  FileList curFiles;
132
+  m_dir.getEntries(ListTrackerFiDi<FIDI>::type(), curFiles);
133
+
134
+  // walk through current list and file/subdir list simultaneously
135
+  FileList::const_iterator itFile = curFiles.begin();
136
+  typename List::iterator  it     = m_list.begin();
137
+  while (itFile != curFiles.end() || it != m_list.end()) {
138
+
139
+    // new entry inserted
140
+    if (it == m_list.end() ||
141
+        (itFile != curFiles.end() && *itFile < it->m_name)) {
142
+      // create object
143
+      Entry entry;
144
+      entry.m_name = *itFile;
145
+      entry.m_pObj = new TYPE(m_parent, *itFile,
146
+                              ListTrackerFiDi<FIDI>::get(m_dir, *itFile));
147
+      if (entry.m_pObj)
148
+        // insert list entry
149
+        m_list.insert(it, entry);
150
+      // advance to next file/subdir
151
+      ++itFile;
152
+    }
153
+
154
+    // entry removed
155
+    else if (itFile == curFiles.end() || *itFile > it->m_name) {
156
+      // remove entry
157
+      delete it->m_pObj;
158
+      it = m_list.erase(it);
159
+      // do not advance to next file/subdir
160
+    }
161
+
162
+    // entry stayed in list
163
+    else {
164
+      // check for update
165
+      it->m_pObj->updateConfig();
166
+      // advance to next file/subdir and next entry
167
+      ++itFile;
168
+      ++it;
169
+    }
170
+
171
+  } // while itFile it
172
+}
173
+
174
+} // namespace Blinker
175
+
176
+#endif // #ifndef LISTTRACKER_IMPL_H
177
+
... ...
@@ -11,6 +11,8 @@
11 11
 #include "CallMgr.h"
12 12
 #include "Directory.h"
13 13
 #include "File.h"
14
+#include "ListTracker.h"
15
+#include "ListTracker_impl.h"
14 16
 #include "Module.h"
15 17
 #include "Priority.h"
16 18
 #include "PriorityInput.h"
... ...
@@ -29,94 +31,28 @@ namespace Blinker {
29 31
 Priority::Priority(CallMgr &callMgr, StreamMgr &streamMgr,
30 32
                    const Directory &dirBase):
31 33
   Module(callMgr, streamMgr, dirBase),
32
-  m_dirInputs(dirBase.getSubdir("inputs")),
33 34
   m_fileOutStream(dirBase.getFile("outstream"), streamMgr),
34
-  m_itCurIn(m_inList.rend())
35
+  m_inListTracker(*this, dirBase.getSubdir("inputs")),
36
+  m_itCurIn(m_inListTracker.m_list.rend())
35 37
 {
36
-  // set up
37
-  updateInListFull();
38 38
 }
39 39
 
40 40
 /// virtual destructor
41 41
 Priority::~Priority()
42 42
 {
43
-  // clean up
44
-  while (!m_inList.empty()) {
45
-    delete m_inList.back().m_pInput;
46
-    m_inList.pop_back();
47
-  }
48 43
 }
49 44
 
50 45
 /// check for update of configuration
51 46
 void Priority::updateConfig()
52 47
 {
53
-  // input list update (directory modified -> full, otherwise -> light)
54
-  if (m_dirInputs.checkModified())
55
-    updateInListFull();
56
-  else
57
-    updateInListLight();
48
+  // input list update
49
+  m_inListTracker.updateConfig();
58 50
 
59 51
   // output stream name file was modified -> re-get output stream
60 52
   if (m_fileOutStream.checkModified())
61 53
     m_fileOutStream.update();
62 54
 }
63 55
 
64
-/// light update of input list, i.e. check all entries in current input list
65
-void Priority::updateInListLight()
66
-{
67
-  // walk through all inputs in input list and check for modification
68
-  InList::iterator itIn;
69
-  for (itIn = m_inList.begin(); itIn != m_inList.end(); ++itIn)
70
-    itIn->m_pInput->updateConfig();
71
-}
72
-
73
-/// full update of input list, i.e. scan subdirs in input list directory
74
-void Priority::updateInListFull()
75
-{
76
-  // get list of subdirs in input directory
77
-  typedef std::list<std::string> Subdirlist;
78
-  Subdirlist curSubdirs;
79
-  m_dirInputs.getEntries(Directory::TypeSubdir, curSubdirs);
80
-
81
-  // walk through current input list and subdir list simultaneously
82
-  Subdirlist::const_iterator itSubdir = curSubdirs.begin();
83
-  InList::iterator           itIn     = m_inList.begin();
84
-  while (itSubdir != curSubdirs.end() || itIn != m_inList.end()) {
85
-
86
-    // new input inserted
87
-    if (itIn == m_inList.end() ||
88
-        (itSubdir != curSubdirs.end() && *itSubdir < itIn->m_name)) {
89
-      // create input object
90
-      InEntry inEntry(*itSubdir);
91
-      inEntry.m_pInput = new Input(*this, *itSubdir,
92
-                                   m_dirInputs.getSubdir(*itSubdir));
93
-      if (inEntry.m_pInput)
94
-        // insert input list entry
95
-        m_inList.insert(itIn, inEntry);
96
-      // advance to next subdir
97
-      ++itSubdir;
98
-    }
99
-
100
-    // input removed
101
-    else if (itSubdir == curSubdirs.end() || *itSubdir > itIn->m_name) {
102
-      // remove input
103
-      delete itIn->m_pInput;
104
-      itIn = m_inList.erase(itIn);
105
-      // do not advance to next subdir
106
-    }
107
-
108
-    // input stayed in input list
109
-    else {
110
-      // check for update
111
-      itIn->m_pInput->updateConfig();
112
-      // advance to next file and next entry
113
-      ++itSubdir;
114
-      ++itIn;
115
-    }
116
-
117
-  } // while itSubdir itIn
118
-}
119
-
120 56
 /**
121 57
  * @brief select specific input (called by inputs)
122 58
  * @param[in] input input to select
... ...
@@ -124,8 +60,9 @@ void Priority::updateInListFull()
124 60
 void Priority::select(const Input *pInput)
125 61
 {
126 62
   // search inputs for passed input
127
-  m_itCurIn = m_inList.rbegin();
128
-  while (m_itCurIn != m_inList.rend() && m_itCurIn->m_pInput != pInput)
63
+  m_itCurIn = m_inListTracker.m_list.rbegin();
64
+  while (m_itCurIn != m_inListTracker.m_list.rend() &&
65
+         m_itCurIn->m_pObj != pInput)
129 66
     ++m_itCurIn;
130 67
 
131 68
   // send current frame
... ...
@@ -138,9 +75,9 @@ void Priority::selectLower()
138 75
   stBlinkenFrame *pFrame;
139 76
 
140 77
   // search inputs with lower priority until a frame is found
141
-  while (m_itCurIn != m_inList.rend()) {
78
+  while (m_itCurIn != m_inListTracker.m_list.rend()) {
142 79
     // check for frame
143
-    if ((pFrame = m_itCurIn->m_pInput->getCurFrame())) {
80
+    if ((pFrame = m_itCurIn->m_pObj->getCurFrame())) {
144 81
       // frame found -> keep this input as current, send frame
145 82
       m_fileOutStream.setFrame(pFrame);
146 83
       return;
... ...
@@ -159,24 +96,13 @@ void Priority::curFrame()
159 96
   stBlinkenFrame *pFrame;
160 97
 
161 98
   // current input available and frame it it available -> send frame
162
-  if (m_itCurIn != m_inList.rend() &&
163
-      (pFrame = m_itCurIn->m_pInput->getCurFrame()))
99
+  if (m_itCurIn != m_inListTracker.m_list.rend() &&
100
+      (pFrame = m_itCurIn->m_pObj->getCurFrame()))
164 101
     m_fileOutStream.setFrame(pFrame);
165 102
   // no frame available -> send this information
166 103
   else
167 104
     m_fileOutStream.setFrame(NULL);
168 105
 }
169 106
 
170
-/* #####################
171
-   # Priority::InEntry #
172
-   ##################### */
173
-
174
-/// constructor
175
-Priority::InEntry::InEntry(const std::string &name):
176
-  m_name(name),
177
-  m_pInput(NULL)
178
-{
179
-}
180
-
181 107
 } // namespace Blinker
182 108
 
... ...
@@ -14,6 +14,7 @@
14 14
 #include "CallMgr.h"
15 15
 #include "Directory.h"
16 16
 #include "File.h"
17
+#include "ListTracker.h"
17 18
 #include "Module.h"
18 19
 #include "OutStreamFile.h"
19 20
 #include "StreamMgr.h"
... ...
@@ -27,18 +28,11 @@ protected:
27 28
   /// input to priority based selector
28 29
   class Input;
29 30
 
30
-  /// input list entry
31
-  struct InEntry {
32
-    std::string m_name;    ///< name of input list entry
33
-    Input       *m_pInput; ///< input object
34
-    InEntry(const std::string &name); ///< constructor
35
-  };
36
-
37
-  /// input list
38
-  typedef std::list<InEntry> InList;
31
+  /// input list tracker
32
+  typedef ListTracker<Priority, Input, Directory> InListTracker;
39 33
 
40 34
   /// input list iterator
41
-  typedef InList::const_reverse_iterator InListIt;
35
+  typedef InListTracker::ListIt InListIt;
42 36
 
43 37
 public:
44 38
   /**
... ...
@@ -64,12 +58,6 @@ public:
64 58
   virtual void updateConfig();
65 59
 
66 60
 protected:
67
-  /// light update of input list, i.e. check all entries in current input list
68
-  void updateInListLight();
69
-
70
-  /// full update of input list, i.e. scan subdirs in input list directory
71
-  void updateInListFull();
72
-
73 61
   /**
74 62
    * @brief select specific input (called by inputs)
75 63
    * @param[in] input input to select
... ...
@@ -83,9 +71,8 @@ protected:
83 71
   void curFrame();
84 72
 
85 73
 protected:
86
-  Directory     m_dirInputs;      ///< input stream directory
87 74
   OutStreamFile m_fileOutStream;  ///< output stream name file
88
-  InList        m_inList;         ///< current input list
75
+  InListTracker m_inListTracker;  ///< input list tracker
89 76
   InListIt      m_itCurIn;        ///< current input
90 77
 }; // class Priority
91 78
 
... ...
@@ -84,13 +84,13 @@ void Priority::Input::frame(stBlinkenFrame *pFrame)
84 84
   if (pFrame) {
85 85
 
86 86
     // if we are current input
87
-    if (m_priority.m_itCurIn != m_priority.m_inList.rend() &&
88
-        m_priority.m_itCurIn->m_pInput == this)
87
+    if (m_priority.m_itCurIn != m_priority.m_inListTracker.m_list.rend() &&
88
+        m_priority.m_itCurIn->m_pObj == this)
89 89
       // pass on frame
90 90
       m_priority.m_fileOutStream.setFrame(pFrame);
91 91
 
92 92
     // we have a higher priority than current input
93
-    if (m_priority.m_itCurIn == m_priority.m_inList.rend() ||
93
+    if (m_priority.m_itCurIn == m_priority.m_inListTracker.m_list.rend() ||
94 94
         m_priority.m_itCurIn->m_name < m_name)
95 95
       // tell priority based selector to select us as input
96 96
       m_priority.select(this);
... ...
@@ -100,8 +100,8 @@ void Priority::Input::frame(stBlinkenFrame *pFrame)
100 100
   else {
101 101
 
102 102
     // if we are current input
103
-    if (m_priority.m_itCurIn != m_priority.m_inList.rend() &&
104
-        m_priority.m_itCurIn->m_pInput == this)
103
+    if (m_priority.m_itCurIn != m_priority.m_inListTracker.m_list.rend() &&
104
+        m_priority.m_itCurIn->m_pObj == this)
105 105
       // tell priority based selector to select lower priority input
106 106
       m_priority.selectLower();
107 107
 
108 108