Commit 1abcfbdc5fae0621a3373bc589a7aac339ce6426

Authored by Charles Otto
1 parent 5bab078d

Make project on timeVaryingTransforms safer

Add a TimeInvariantWrapperTransform member of TimeVaryingTransform, and use
that in TimeVaryingTransform::project for thread safety.

This is the strategy previously used in Distribute, but putting the alias on
TimeVaryingTransform gives us more safety if Distribute is not in fact the
top level transform.

Note: copies are only made off of calls to project, so having the alias on
every TimeVaryingTransform is not too wasteful.
openbr/plugins/meta.cpp
... ... @@ -264,7 +264,6 @@ class ContractTransform : public UntrainableMetaTransform
264 264  
265 265 virtual void project(const TemplateList &src, TemplateList &dst) const
266 266 {
267   - //dst = Expanded(src);
268 267 if (src.empty()) return;
269 268 Template out;
270 269  
... ... @@ -682,8 +681,10 @@ public:
682 681  
683 682 void init()
684 683 {
685   - if (transform && transform->timeVarying())
686   - transform = new br::TimeInvariantWrapperTransform(transform);
  684 + if (!transform)
  685 + return;
  686 +
  687 + trainable = transform->trainable;
687 688 }
688 689  
689 690 };
... ...
openbr/plugins/openbr_internal.h
... ... @@ -24,81 +24,27 @@ private:
24 24 };
25 25  
26 26 /*!
27   - * \brief A br::MetaTransform that does not require training data.
  27 + * \brief A br::Transform expecting multiple matrices per template.
28 28 */
29   -class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform
  29 +class BR_EXPORT MetaTransform : public Transform
30 30 {
31 31 Q_OBJECT
32 32  
33 33 protected:
34   - UntrainableMetaTransform() : UntrainableTransform(false) {}
35   -};
36   -
37   -/*!
38   - * \brief A br::Transform for which the results of project may change due to prior calls to project
39   - */
40   -class BR_EXPORT TimeVaryingTransform : public Transform
41   -{
42   - Q_OBJECT
43   -
44   -public:
45   - virtual bool timeVarying() const { return true; }
46   -
47   - virtual void project(const Template &src, Template &dst) const
48   - {
49   - qFatal("No const project defined for time-varying transform");
50   - (void) dst; (void) src;
51   - }
52   -
53   - virtual void project(const TemplateList &src, TemplateList &dst) const
54   - {
55   - qFatal("No const project defined for time-varying transform");
56   - (void) dst; (void) src;
57   - }
58   -
59   - // Get a compile failure if this isn't here to go along with the other
60   - // projectUpdate, no idea why
61   - virtual void projectUpdate(const Template & src, Template & dst)
62   - {
63   - (void) src; (void) dst;
64   - qFatal("do something useful");
65   - }
66   -
67   - virtual void projectUpdate(const TemplateList &src, TemplateList &dst)
68   - {
69   - foreach (const Template & src_part, src) {
70   - Template out;
71   - projectUpdate(src_part, out);
72   - dst.append(out);
73   - }
74   - }
75   -
76   - /*!
77   - *\brief For transforms that don't do any training, this default implementation
78   - * which creates a new copy of the Transform from its description string is sufficient.
79   - */
80   - virtual Transform * smartCopy()
81   - {
82   - return this->clone();
83   - }
84   -
85   -
86   -protected:
87   - TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable) {}
  34 + MetaTransform() : Transform(false) {}
88 35 };
89 36  
90 37 /*!
91   - * \brief A br::Transform expecting multiple matrices per template.
  38 + * \brief A br::MetaTransform that does not require training data.
92 39 */
93   -class BR_EXPORT MetaTransform : public Transform
  40 +class BR_EXPORT UntrainableMetaTransform : public UntrainableTransform
94 41 {
95 42 Q_OBJECT
96 43  
97 44 protected:
98   - MetaTransform() : Transform(false) {}
  45 + UntrainableMetaTransform() : UntrainableTransform(false) {}
99 46 };
100 47  
101   -
102 48 class TransformCopier : public ResourceMaker<Transform>
103 49 {
104 50 public:
... ... @@ -151,6 +97,71 @@ private:
151 97 Transform * baseTransform;
152 98 };
153 99  
  100 +/*!
  101 + * \brief A br::Transform for which the results of project may change due to prior calls to project
  102 + */
  103 +class BR_EXPORT TimeVaryingTransform : public Transform
  104 +{
  105 + Q_OBJECT
  106 +
  107 +public:
  108 +
  109 + virtual bool timeVarying() const { return true; }
  110 +
  111 + virtual void project(const Template &src, Template &dst) const
  112 + {
  113 + timeInvariantAlias->project(src,dst);
  114 + }
  115 +
  116 + virtual void project(const TemplateList &src, TemplateList &dst) const
  117 + {
  118 + timeInvariantAlias->project(src,dst);
  119 + }
  120 +
  121 + // Get a compile failure if this isn't here to go along with the other
  122 + // projectUpdate, no idea why
  123 + virtual void projectUpdate(const Template & src, Template & dst)
  124 + {
  125 + (void) src; (void) dst;
  126 + qFatal("do something useful");
  127 + }
  128 +
  129 + virtual void projectUpdate(const TemplateList &src, TemplateList &dst)
  130 + {
  131 + foreach (const Template & src_part, src) {
  132 + Template out;
  133 + projectUpdate(src_part, out);
  134 + dst.append(out);
  135 + }
  136 + }
  137 +
  138 + /*!
  139 + *\brief For transforms that don't do any training, this default implementation
  140 + * which creates a new copy of the Transform from its description string is sufficient.
  141 + */
  142 + virtual Transform * smartCopy()
  143 + {
  144 + return this->clone();
  145 + }
  146 +
  147 + void init()
  148 + {
  149 + delete timeInvariantAlias;
  150 + timeInvariantAlias = new TimeInvariantWrapperTransform(this);
  151 + }
  152 +
  153 +protected:
  154 + Transform * timeInvariantAlias;
  155 + TimeVaryingTransform(bool independent = true, bool trainable = true) : Transform(independent, trainable)
  156 + {
  157 + timeInvariantAlias = NULL;
  158 + }
  159 + ~TimeVaryingTransform()
  160 + {
  161 + delete timeInvariantAlias;
  162 + }
  163 +};
  164 +
154 165  
155 166 /*!
156 167 * \brief A MetaTransform that aggregates some sub-transforms
... ... @@ -165,15 +176,17 @@ public:
165 176  
166 177 virtual void project(const Template &src, Template &dst) const
167 178 {
168   - if (timeVarying()) qFatal("No const project defined for time-varying transform");
  179 + if (timeVarying()) {
  180 + timeInvariantAlias->project(src,dst);
  181 + return;
  182 + }
169 183 _project(src, dst);
170 184 }
171 185  
172 186 virtual void project(const TemplateList &src, TemplateList &dst) const
173 187 {
174 188 if (timeVarying()) {
175   - CompositeTransform * non_const = const_cast<CompositeTransform *>(this);
176   - non_const->projectUpdate(src,dst);
  189 + timeInvariantAlias->project(src,dst);
177 190 return;
178 191 }
179 192 _project(src, dst);
... ... @@ -190,6 +203,10 @@ public:
190 203 isTimeVarying = isTimeVarying || transform->timeVarying();
191 204 trainable = trainable || transform->trainable;
192 205 }
  206 +
  207 + // If we are time varying, set up timeInvariantAlias
  208 + if (this->timeVarying())
  209 + TimeVaryingTransform::init();
193 210 }
194 211  
195 212 /*!
... ...
openbr/plugins/stream.cpp
... ... @@ -707,8 +707,7 @@ public:
707 707 if (input == NULL) {
708 708 qFatal("null input to multi-thread stage");
709 709 }
710   - // Project the input we got
711   - transform->projectUpdate(input->data);
  710 + input->data >> *transform;
712 711  
713 712 should_continue = nextStage->tryAcquireNextStage(input);
714 713  
... ... @@ -1300,6 +1299,12 @@ public:
1300 1299 {
1301 1300 if (!transform)
1302 1301 return;
  1302 +
  1303 + // Set up timeInvariantAlias
  1304 + // this is only safe because copies are actually made in project
  1305 + // calls, not during init.
  1306 + TimeVaryingTransform::init();
  1307 +
1303 1308 trainable = transform->trainable;
1304 1309  
1305 1310 basis.setParent(this->parent());
... ...