ArnLib  4.0.x
Active Registry Network
ArnLink.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2022 Michael Wiklund.
2 // All rights reserved.
3 // Contact: arnlib@wiklunden.se
4 //
5 // This file is part of the ArnLib - Active Registry Network.
6 // Parts of ArnLib depend on Qt and/or other libraries that have their own
7 // licenses. Usage of these other libraries is subject to their respective
8 // license agreements.
9 //
10 // GNU Lesser General Public License Usage
11 // This file may be used under the terms of the GNU Lesser General Public
12 // License version 2.1 as published by the Free Software Foundation and
13 // appearing in the file LICENSE_LGPL.txt included in the packaging of this
14 // file. In addition, as a special exception, you may use the rights described
15 // in the Nokia Qt LGPL Exception version 1.1, included in the file
16 // LGPL_EXCEPTION.txt in this package.
17 //
18 // GNU General Public License Usage
19 // Alternatively, this file may be used under the terms of the GNU General Public
20 // License version 3.0 as published by the Free Software Foundation and appearing
21 // in the file LICENSE_GPL.txt included in the packaging of this file.
22 //
23 // Other Usage
24 // Alternatively, this file may be used in accordance with the terms and conditions
25 // contained in a signed written agreement between you and Michael Wiklund.
26 //
27 // This program is distributed in the hope that it will be useful, but WITHOUT ANY
28 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
29 // PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
30 //
31 
32 #include "ArnLink.hpp"
33 #include "ArnInc/ArnLib.hpp"
34 #include "ArnInc/ArnEvent.hpp"
35 #include <QCoreApplication>
36 #include <QThread>
37 #include <limits>
38 #include <QDebug>
39 
40 QAtomicInt ArnLink::_idCount(1);
41 
42 
43 struct ArnLinkValue {
44  QString valueString;
45  QByteArray valueByteArray;
46  QVariant valueVariant;
47  volatile ARNREAL valueReal;
48  volatile int valueInt;
49  quint32 localUpdateCount; // Also ignored updates (ignoreSameValue) are included
50 
52  valueReal = 0.0;
53  valueInt = 0;
54  localUpdateCount = 0;
55  }
56 };
57 
58 
59 ArnLink::ArnLink( ArnLink *parent, const QString& name, Arn::LinkFlags flags)
60 {
61  static ArnLinkList nullArnLinkList;
62 
63  QString name_ = Arn::convertBaseName( name, Arn::NameF());
64 
65  _parent = arnNullptr;
66  _objectName = name_;
67  _isFolder = flags.is( flags.Folder);
68  _isProvider = name_.endsWith('!');
69  _type = Arn::DataType::Null;
70  _twin = arnNullptr;
71  _subscribeTab = arnNullptr;
72  _mutex = arnNullptr;
73  _children = _isFolder ? new ArnLinkList : &nullArnLinkList;
74  _val = _isFolder ? arnNullptr : new ArnLinkValue;
75  _isPipeMode = false;
76  _isSaveMode = false;
77  _hasBeenSetup = false;
78  _syncMode = 0;
79  _id = quint32( _idCount.fetchAndAddRelaxed(1));
80  _refCount = -1; // Mark no reference, Ok to delete
81  _zeroRefCount = 0;
82  _isRetired = false;
83  _retireType = RetireType::None;
84  setParent( parent);
85  resetHave();
86 }
87 
88 
89 ArnLink::~ArnLink()
90 {
91  if (Arn::debugLinkDestroy) qDebug() << "Destructor link: path=" << linkPath();
92  if (_mutex)
93  delete _mutex;
94  if (_subscribeTab)
95  delete _subscribeTab;
96 
97  if (_twin) {
98  _twin->_twin = arnNullptr; // points to this object
99  delete _twin;
100  _twin = arnNullptr;
101  }
102 
103  setParent( arnNullptr);
104 }
105 
106 
107 void ArnLink::resetHave()
108 {
109  _haveInt = false;
110  _haveReal = false;
111  _haveString = false;
112  _haveByteArray = false;
113  _haveVariant = false;
114 }
115 
116 
117 void ArnLink::needInt( bool* isOk)
118 {
119  if (!_haveInt) {
120  bool isOk2 = true; // Default
121  switch (_type) {
122  case Arn::DataType::Real:
123  _val->valueInt = int( _val->valueReal);
124  break;
126  _val->valueInt = _val->valueString.toInt( &isOk2);
127  break;
129  _val->valueInt = _val->valueByteArray.toInt( &isOk2);
130  break;
132  _val->valueInt = _val->valueVariant.toInt( &isOk2);
133  break;
134  default:
135  _val->valueInt = 0;
136  isOk2 = false;
137  }
138  _haveInt = isOk2;
139  if (isOk)
140  *isOk = isOk2;
141  }
142 }
143 
144 
145 void ArnLink::needReal( bool* isOk)
146 {
147  if (!_haveReal) {
148  bool isOk2 = true; // Default
149  switch (_type) {
150  case Arn::DataType::Int:
151  _val->valueReal = (ARNREAL)_val->valueInt;
152  break;
153 #if defined( ARNREAL_FLOAT)
155  _val->valueReal = _val->valueString.toFloat( &isOk2);
156  break;
158  _val->valueReal = _val->valueByteArray.toFloat( &isOk2);
159  break;
161  _val->valueReal = _val->valueVariant.toFloat( &isOk2);
162  break;
163 #else
165  _val->valueReal = _val->valueString.toDouble( &isOk2);
166  break;
168  _val->valueReal = _val->valueByteArray.toDouble( &isOk2);
169  break;
171  _val->valueReal = _val->valueVariant.toDouble( &isOk2);
172  break;
173 #endif
174  default:
175  _val->valueReal = 0.0;
176  isOk2 = false;
177  }
178  _haveReal = isOk2;
179  if (isOk)
180  *isOk = isOk2;
181  }
182 }
183 
184 
185 QString ArnLink::objectName() const
186 {
187  return _objectName;
188 }
189 
190 
191 ArnLink* ArnLink::parent() const
192 {
193  return _parent;
194 }
195 
196 
197 void ArnLink::setParent( ArnLink* parent)
198 {
199  if (_parent)
200  _parent->_children->removeOne( this);
201 
202  _parent = parent;
203 
204  if (_parent)
205  _parent->_children->append( this);
206 }
207 
208 
209 const ArnLinkList& ArnLink::children() const
210 {
211  return *_children;
212 }
213 
214 
216 void ArnLink::doValueChanged( int sendId, const QByteArray* valueData,
217  const ArnLinkHandle& handleData)
218 {
219  // qDebug() << "doValueChanged: isThr=" << (_mutex != arnNullptr) << " isPipe=" << _isPipeMode <<
220  // " path=" << linkPath() << " value=" << (valueData ? *valueData : toByteArray());
221  ArnEvValueChange ev( sendId, valueData, handleData);
222  sendArnEvent( &ev);
223 }
224 
225 
226 void ArnLink::sendEventsInThread( ArnEvent* ev, const ArnCoreItemList& recipients)
227 {
228  int len = recipients.size();
229  for (int i = 0; i < len; ++i) {
230  ArnCoreItem* coreItem = recipients.at(i);
231  ev->setAccepted( true); // Default
232  coreItem->sendArnEventItem( ev, false);
233  }
234 }
235 
236 
238 void ArnLink::sendArnEvent( ArnEvent* ev)
239 {
240  if (!_mutex) { // Fast non threaded version
241  // Copy of subsribeTab due to destroyEvent can change it
242  if (_subscribeTab)
243  sendEventsInThread( ev, ArnCoreItemList( *_subscribeTab));
244  return;
245  }
246 
247  _mutex->lock();
248 
249  ArnCoreItemList subscrInThread;
250  QThread* curThread = QThread::currentThread();
251 
252  if (_subscribeTab && !_subscribeTab->isEmpty()) {
253  foreach (ArnCoreItem* coreItem, *_subscribeTab) {
254  if (coreItem->thread() == curThread) {
255  subscrInThread += coreItem;
256  }
257  else {
258  // Recipient in different thread
259  ArnEvent* evClone = ev->makeHeapClone();
260  coreItem->sendArnEventItem( evClone, true, true);
261  }
262  }
263  }
264 
265  _mutex->unlock();
266 
267  sendEventsInThread( ev, subscrInThread);
268 }
269 
270 
271 void ArnLink::sendEventsDirRoot( ArnEvent* ev, ArnLink* startLink)
272 {
273  ArnLink* link = startLink;
274  while (link) {
275  // qDebug() << "sendEventsDirRoot: inLinkPath=" << link->linkPath() << " ev=" << ev->toString();
276  link->sendArnEvent( ev);
277  link = link->parent();
278  }
279 }
280 
281 
282 void ArnLink::sendEventArnM( ArnEvent* ev)
283 {
284  bool isMainThread = true; // Default
285  QObject* objArnM = arnM();
286 
287  if (_mutex) {
288  if (QThread::currentThread() != objArnM->thread()) {
289  isMainThread = false;
290  ArnEvent* evClone = ev->makeHeapClone();
291  QCoreApplication::postEvent( objArnM, evClone);
292  }
293  }
294 
295  if (isMainThread) {
296  QCoreApplication::sendEvent( objArnM, ev);
297  }
298 }
299 
300 
301 void ArnLink::setValue( int value, int sendId, bool useUncrossed)
302 {
303  if (!_val) return;
304  if (_twin && !useUncrossed) { // support for bidirectional function
305  _twin->setValue( value, sendId, true);
306  return;
307  }
308 
309  if (_mutex) _mutex->lock();
310  resetHave();
311  _val->valueInt = value;
312  _type = Arn::DataType::Int;
313  _haveInt = true;
314  ++_val->localUpdateCount;
315  if (_mutex) _mutex->unlock();
316 
317  if (_mutex && _isPipeMode) {
318  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
319  QByteArray::number( value);
320  doValueChanged( sendId, &valueData);
321  }
322  else {
323  doValueChanged( sendId);
324  }
325 }
326 
327 
328 void ArnLink::setValue( ARNREAL value, int sendId, bool useUncrossed)
329 {
330  if (!_val) return;
331  if (_twin && !useUncrossed) { // support for bidirectional function
332  _twin->setValue( value, sendId, true);
333  return;
334  }
335 
336  if (_mutex) _mutex->lock();
337  resetHave();
338  _val->valueReal = value;
339  _type = Arn::DataType::Real;
340  _haveReal = true;
341  ++_val->localUpdateCount;
342  if (_mutex) _mutex->unlock();
343 
344  if (_mutex && _isPipeMode) {
345 #if defined( ARNREAL_FLOAT)
346  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
347  QByteArray::number( value, 'g', std::numeric_limits<float>::digits10);
348 #else
349  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
350  QByteArray::number( value, 'g', std::numeric_limits<double>::digits10);
351 #endif
352  doValueChanged( sendId, &valueData);
353  }
354  else {
355  doValueChanged( sendId);
356  }
357 }
358 
359 
360 void ArnLink::setValue( const QString& value, int sendId, bool useUncrossed,
361  const ArnLinkHandle& handleData)
362 {
363  if (!_val) return;
364  if (_twin && !useUncrossed) { // support for bidirectional function
365  _twin->setValue( value, sendId, true, handleData);
366  return;
367  }
368 
369  if (_mutex) _mutex->lock();
370  resetHave();
371  _val->valueString.resize(0); // Avoid heap defragmentation
372  _val->valueString += value;
373  _type = Arn::DataType::String;
374  _haveString = true;
375  if (!handleData.flags().is( ArnLinkHandle::Flags::FromRemote))
376  ++_val->localUpdateCount;
377  if (_mutex) _mutex->unlock();
378 
379  if (_mutex && (_isPipeMode || !handleData.isNull())) {
380  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
381  value.toUtf8();
382  doValueChanged( sendId, &valueData, handleData);
383  }
384  else {
385  doValueChanged( sendId, arnNullptr, handleData);
386  }
387 }
388 
389 
390 void ArnLink::setValue( const QByteArray& value, int sendId, bool useUncrossed,
391  const ArnLinkHandle& handleData)
392 {
393  if (!_val) return;
394  if (_twin && !useUncrossed) { // support for bidirectional function
395  _twin->setValue( value, sendId, true, handleData);
396  return;
397  }
398 
399  if (_mutex) _mutex->lock();
400  resetHave();
401  _val->valueByteArray.resize(0); // Avoid heap defragmentation
402  _val->valueByteArray += value;
403  _type = Arn::DataType::ByteArray;
404  _haveByteArray = true;
405  if (!handleData.flags().is( ArnLinkHandle::Flags::FromRemote))
406  ++_val->localUpdateCount;
407  if (_mutex) _mutex->unlock();
408 
409  if (_mutex && (_isPipeMode || !handleData.isNull())) {
410  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::ByteArray)) + value;
411  doValueChanged( sendId, &valueData, handleData);
412  }
413  else {
414  doValueChanged( sendId, arnNullptr, handleData);
415  }
416 }
417 
418 
419 void ArnLink::setValue( const QVariant& value, int sendId, bool useUncrossed,
420  const ArnLinkHandle& handleData)
421 {
422  if (!_val) return;
423  if (_twin && !useUncrossed) { // support for bidirectional function
424  _twin->setValue( value, sendId, true, handleData);
425  return;
426  }
427 
428  if (_mutex) _mutex->lock();
429  resetHave();
430  _val->valueVariant = value;
431  _type = Arn::DataType::Variant;
432  _haveVariant = true;
433  if (!handleData.flags().is( ArnLinkHandle::Flags::FromRemote))
434  ++_val->localUpdateCount;
435  if (_mutex) _mutex->unlock();
436 
437  if (_mutex && _isPipeMode) {
438  // In a pipe only QVariant:s that can convert to QString is supported
439  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
440  value.toString().toUtf8();
441  doValueChanged( sendId, &valueData, handleData);
442  }
443  else {
444  doValueChanged( sendId, arnNullptr, handleData);
445  }
446 }
447 
448 
449 void ArnLink::setIgnoredValue( const ArnLinkHandle& handleData)
450 {
451  if (!_val) return;
452 
453  if (_mutex) _mutex->lock();
454  if (!handleData.flags().is( ArnLinkHandle::Flags::FromRemote))
455  ++_val->localUpdateCount;
456  if (_mutex) _mutex->unlock();
457 }
458 
459 
460 void ArnLink::setBits( int mask, int value, int sendId, bool useUncrossed)
461 {
462  if (!_val) return;
463 
464  if (_twin) { // support for bidirectional function
465  if (_isAtomicOpProvider && !_twin->_isAtomicOpProvider) { // This twin is OpProvider
466  return _twin->setBits( mask, value, sendId, useUncrossed); // Act as OpProvider for setBits
467  }
468  if (!_twin->_isAtomicOpProvider) { // Neither twin is OpProvider, send out event
469  // qDebug() << "doSetBits: isThr=" << (_mutex != arnNullptr) << " isPipe=" << _isPipeMode <<
470  // " path=" << linkPath() << " mask=" << mask << " value=" << value;
471  ArnEvAtomicOp ev( ArnEvAtomicOp::Op::BitSet, mask, value);
472  _twin->sendArnEvent( &ev);
473  return;
474  }
475  // Other twin is OpProvider (or faulty both is)
476  }
477 
478  if (_mutex) _mutex->lock();
479  needInt();
480 
481  resetHave();
482  int newValue = (_val->valueInt & ~mask) | (value & mask);
483  _val->valueInt = newValue;
484  _type = Arn::DataType::Int;
485  _haveInt = true;
486  ++_val->localUpdateCount;
487 
488  if (_mutex) _mutex->unlock();
489 
490  if (_twin && !useUncrossed) { // Update the OpProvider link before, as if it was requested there first
491  _twin->setValue( newValue, sendId, true);
492  }
493 
494  if (_mutex && _isPipeMode) {
495  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
496  QByteArray::number( newValue);
497  doValueChanged( sendId, &valueData);
498  }
499  else {
500  doValueChanged( sendId);
501  }
502 }
503 
504 
505 void ArnLink::addValue( int value, int sendId, bool useUncrossed)
506 {
507  if (!_val) return;
508 
509  if (_twin) { // support for bidirectional function
510  if (_isAtomicOpProvider && !_twin->_isAtomicOpProvider) { // This twin is OpProvider
511  return _twin->addValue( value, sendId, useUncrossed); // Act as provider for addValue
512  }
513  if (!_twin->_isAtomicOpProvider) { // Neither twin is OpProvider, send out event
514  // qDebug() << "doAddValue: isThr=" << (_mutex != arnNullptr) << " isPipe=" << _isPipeMode <<
515  // " path=" << linkPath() << " value=" << value;
516  ArnEvAtomicOp ev( ArnEvAtomicOp::Op::AddInt, value, QVariant());
517  _twin->sendArnEvent( &ev);
518  return;
519  }
520  // Other twin is OpProvider (or faulty both is)
521  }
522 
523  if (_mutex) _mutex->lock();
524  needInt();
525 
526  resetHave();
527  int newValue = _val->valueInt + value;
528  _val->valueInt = newValue;
529  _type = Arn::DataType::Int;
530  _haveInt = true;
531  ++_val->localUpdateCount;
532 
533  if (_mutex) _mutex->unlock();
534 
535  if (_twin && !useUncrossed) { // Update the OpProvider link before, as if it was requested there first
536  _twin->setValue( newValue, sendId, true);
537  }
538 
539  if (_mutex && _isPipeMode) {
540  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
541  QByteArray::number( newValue);
542  doValueChanged( sendId, &valueData);
543  }
544  else {
545  doValueChanged( sendId);
546  }
547 }
548 
549 
550 void ArnLink::addValue( ARNREAL value, int sendId, bool useUncrossed)
551 {
552  if (!_val) return;
553 
554  if (_twin) { // support for bidirectional function
555  if (_isAtomicOpProvider && !_twin->_isAtomicOpProvider) { // This twin is OpProvider
556  return _twin->addValue( value, sendId, useUncrossed); // Act as provider for addValue
557  }
558  if (!_twin->_isAtomicOpProvider) { // Neither twin is OpProvider, send out event
559  // qDebug() << "doAddValue: isThr=" << (_mutex != arnNullptr) << " isPipe=" << _isPipeMode <<
560  // " path=" << linkPath() << " value=" << value;
561  ArnEvAtomicOp ev( ArnEvAtomicOp::Op::AddReal, value, QVariant());
562  _twin->sendArnEvent( &ev);
563  return;
564  }
565  // Other twin is OpProvider (or faulty both is)
566  }
567 
568  if (_mutex) _mutex->lock();
569  needReal();
570 
571  resetHave();
572  ARNREAL newValue = _val->valueReal + value;
573  _val->valueReal = newValue;
574  _type = Arn::DataType::Real;
575  _haveReal = true;
576  ++_val->localUpdateCount;
577 
578  if (_mutex) _mutex->unlock();
579 
580  if (_twin && !useUncrossed) { // Update the OpProvider link before, as if it was requested there first
581  _twin->setValue( newValue, sendId, true);
582  }
583 
584  if (_mutex && _isPipeMode) {
585  QByteArray valueData = QByteArray( 1, char( Arn::ExportCode::String)) +
586  QByteArray::number( newValue);
587  doValueChanged( sendId, &valueData);
588  }
589  else {
590  doValueChanged( sendId);
591  }
592 }
593 
594 
595 int ArnLink::toInt( bool* isOk)
596 {
597  if (isOk)
598  *isOk = true; // Default
599  if (!_val) return 0;
600  if (_mutex) _mutex->lock();
601 
602  needInt( isOk);
603 
604  if (_mutex) {
605  int retVal = _val->valueInt;
606  _mutex->unlock();
607  return retVal;
608  }
609  return _val->valueInt;
610 }
611 
612 
613 ARNREAL ArnLink::toReal( bool* isOk)
614 {
615  if (isOk)
616  *isOk = true; // Default
617  if (!_val) return 0.0;
618  if (_mutex) _mutex->lock();
619 
620  needReal( isOk);
621 
622  if (_mutex) {
623  ARNREAL retVal = _val->valueReal;
624  _mutex->unlock();
625  return retVal;
626  }
627  return _val->valueReal;
628 }
629 
630 
631 QString ArnLink::toString( bool* isOk)
632 {
633  if (isOk)
634  *isOk = true; // Default
635  if (!_val) return QString();
636  if (_mutex) _mutex->lock();
637 
638  if (!_haveString) {
639  bool isOk2 = true; // Default
640  _val->valueString.resize(0); // Avoid heap defragmentation
641  switch (_type) {
642  case Arn::DataType::Int:
643  _val->valueString += QString::number(_val->valueInt, 10);
644  break;
645  case Arn::DataType::Real:
646 #if defined( ARNREAL_FLOAT)
647  _val->valueString += QString::number(_val->valueReal, 'g', std::numeric_limits<float>::digits10);
648 #else
649  _val->valueString += QString::number(_val->valueReal, 'g', std::numeric_limits<double>::digits10);
650 #endif
651  break;
653  _val->valueString += QString::fromUtf8( _val->valueByteArray.constData(), _val->valueByteArray.size());
654  break;
656  isOk2 = _val->valueVariant.canConvert( QVariant::String);
657  _val->valueString += _val->valueVariant.toString();
658  break;
659  default:
660  isOk2 = false;
661  }
662  _haveString = isOk2;
663  if (isOk)
664  *isOk = isOk2;
665  }
666 
667  if (_mutex) {
668  QString retVal = _val->valueString;
669  _mutex->unlock();
670  return retVal;
671  }
672  return _val->valueString;
673 }
674 
675 
676 QByteArray ArnLink::toByteArray( bool* isOk)
677 {
678  if (isOk)
679  *isOk = true; // Default
680  if (!_val) return QByteArray();
681  if (_mutex) _mutex->lock();
682 
683  if (!_haveByteArray) {
684  bool isOk2 = true; // Default
685  _val->valueByteArray.resize(0); // Avoid heap defragmentation
686  switch (_type) {
687  case Arn::DataType::Int:
688  _val->valueByteArray += QByteArray::number( _val->valueInt, 10);
689  break;
690  case Arn::DataType::Real:
691 #if defined( ARNREAL_FLOAT)
692  _val->valueByteArray += QByteArray::number( _val->valueReal, 'g', std::numeric_limits<float>::digits10);
693 #else
694  _val->valueByteArray += QByteArray::number( _val->valueReal, 'g', std::numeric_limits<double>::digits10);
695 #endif
696  break;
698  _val->valueByteArray += _val->valueString.toUtf8();
699  break;
701  isOk2 = _val->valueVariant.canConvert( QVariant::String);
702  _val->valueByteArray += _val->valueVariant.toString().toUtf8();
703  break;
704  default:
705  isOk2 = false;
706  }
707  _haveByteArray = isOk2;
708  if (isOk)
709  *isOk = isOk2;
710  }
711 
712  if (_mutex) {
713  QByteArray retVal = _val->valueByteArray;
714  _mutex->unlock();
715  return retVal;
716  }
717  return _val->valueByteArray;
718 }
719 
720 
721 QVariant ArnLink::toVariant( bool* isOk)
722 {
723  if (isOk)
724  *isOk = true; // Default
725  if (!_val) return QVariant();
726  if (_mutex) _mutex->lock();
727 
728  if (!_haveVariant) {
729  bool isOk2 = true; // Default
730  switch (_type) {
731  case Arn::DataType::Int:
732  _val->valueVariant = _val->valueInt;
733  break;
734  case Arn::DataType::Real:
735  _val->valueVariant = _val->valueReal;
736  break;
738  _val->valueVariant = _val->valueString;
739  break;
741  _val->valueVariant = QString::fromUtf8( _val->valueByteArray.constData(),
742  _val->valueByteArray.size());
743  break;
744  default:
745  _val->valueVariant = QVariant();
746  isOk2 = false;
747  }
748  _haveVariant = isOk2;
749  if (isOk)
750  *isOk = isOk2;
751  }
752 
753  if (_mutex) {
754  QVariant retVal = _val->valueVariant;
755  _mutex->unlock();
756  return retVal;
757  }
758  return _val->valueVariant;
759 }
760 
761 
762 Arn::DataType ArnLink::type()
763 {
764  if (_mutex) _mutex->lock();
765  Arn::DataType retVal = Arn::DataType::fromInt( _type);
766  if (_mutex) _mutex->unlock();
767 
768  return retVal;
769 }
770 
771 
772 QString ArnLink::linkPath( Arn::NameF nameF)
773 {
774  nameF.set( nameF.NoFolderMark, false); // Foldermark '/' must be ...
775  QString path;
776  QString linkName;
777  ArnLink* link = this;
778 
779  while (link) { // Backwards until root
780  ArnLink* parentLink = link->parent();
781  if (!parentLink) {
782  if (nameF.is( nameF.Relative)) break; // Skip Root
783  nameF.set( nameF.EmptyOk, true); // Root is Empty node name
784  }
785  linkName = link->linkName( nameF);
786  path.insert(0, linkName);
787  link = parentLink;
788  }
789 
790  return path;
791 }
792 
793 
794 QString ArnLink::linkName( Arn::NameF nameF)
795 {
796  QString retVal = convertBaseName( objectName(), nameF);
797  if (this->isFolder() && !nameF.is(( nameF.NoFolderMark)))
798  retVal += '/';
799 
800  return retVal;
801 }
802 
803 
804 uint ArnLink::linkId() const
805 {
806  return _id;
807 }
808 
809 
810 void ArnLink::setupEnd( const QString& path, Arn::ObjectSyncMode syncMode, Arn::LinkFlags flags)
811 {
812  if (!_hasBeenSetup) {
813  _hasBeenSetup = true;
814  addSyncMode( syncMode);
815 
816  ArnEvLinkCreate arnEvLinkCreate( path, this, flags.is( flags.LastLink));
817  sendEventsDirRoot( &arnEvLinkCreate, parent());
818  }
819 }
820 
821 
822 void ArnLink::doModeChanged()
823 {
824  ArnEvModeChange arnEvModeChange( linkPath(), _id, getMode());
825  sendEventsDirRoot( &arnEvModeChange, this);
826 }
827 
828 
829 ArnLink* ArnLink::findLink( const QString& name)
830 {
831  QString name_ = Arn::convertBaseName( name, Arn::NameF());
832 
833  int childNum = _children->size();
834  for (int i = 0; i < childNum; i++) {
835  ArnLink* child = _children->at(i);
836 
837  if (child->objectName() == name_) {
838  return child;
839  }
840  }
841 
842  return 0;
843 }
844 
845 
846 bool ArnLink::isFolder( void)
847 {
848  return _isFolder;
849 }
850 
851 
852 void ArnLink::addSyncMode( Arn::ObjectSyncMode syncMode)
853 {
854  if (_mutex) _mutex->lock();
855  _syncMode |= syncMode.toInt();
856  if (_mutex) _mutex->unlock();
857 }
858 
859 
860 Arn::ObjectSyncMode ArnLink::syncMode()
861 {
862  if (_mutex) _mutex->lock();
863  int retVal = _syncMode;
864  if (_mutex) _mutex->unlock();
865  return Arn::ObjectSyncMode::fromInt( retVal);
866 }
867 
868 
869 Arn::ObjectMode ArnLink::getMode()
870 {
871  Arn::ObjectMode mode;
872  if (_mutex) _mutex->lock();
873  mode.set( mode.Pipe, _isPipeMode);
874  mode.set( mode.BiDir, _twin != arnNullptr);
875  if (_mutex) _mutex->unlock();
876  mode.set( mode.Save, isSaveMode());
877 
878  return mode;
879 }
880 
881 
882 bool ArnLink::isBiDirMode()
883 {
884  return _twin != arnNullptr; // Having a twin is bidirectional mode
885 }
886 
887 
888 void ArnLink::setPipeMode( bool isPipeMode, bool alsoSetTwin)
889 {
890  if (_mutex) _mutex->lock();
891  if (isPipeMode != _isPipeMode) {
892  _isPipeMode = isPipeMode;
893  if (_mutex) _mutex->unlock();
894  doModeChanged();
895  if (_mutex) _mutex->lock();
896  }
897  if (_twin && alsoSetTwin) {
898  if (_mutex) _mutex->unlock();
899  _twin->setPipeMode( isPipeMode, false);
900  if (_mutex) _mutex->lock();
901  }
902  if (_mutex) _mutex->unlock();
903 }
904 
905 
906 bool ArnLink::isPipeMode()
907 {
908  if (_mutex) _mutex->lock();
909  bool retVal = _isPipeMode;
910  if (_mutex) _mutex->unlock();
911  return retVal;
912 }
913 
914 
915 void ArnLink::setSaveMode( bool isSaveMode)
916 {
917  ArnLink* link = valueLink(); // SaveMode is always stored in ValueLink
918  if (this != link) return link->setSaveMode( isSaveMode);
919 
920  if (_mutex) _mutex->lock();
921  if (isSaveMode != _isSaveMode) {
922  _isSaveMode = isSaveMode;
923  if (_mutex) _mutex->unlock();
924  doModeChanged();
925  return;
926  }
927  if (_mutex) _mutex->unlock();
928 }
929 
930 
931 bool ArnLink::isSaveMode()
932 {
933  ArnLink* link = valueLink(); // SaveMode is always stored in ValueLink
934  if (this != link) return link->isSaveMode();
935 
936  if (_mutex) _mutex->lock();
937  bool retVal = _isSaveMode;
938  if (_mutex) _mutex->unlock();
939  return retVal;
940 }
941 
942 
943 void ArnLink::setAtomicOpProvider( bool isProvider)
944 {
945  _isAtomicOpProvider = isProvider;
946 }
947 
948 
949 bool ArnLink::isAtomicOpProvider() const
950 {
951  return _isAtomicOpProvider;
952 }
953 
954 
955 bool ArnLink::isProvider() const
956 {
957  return _isProvider;
958 }
959 
960 
961 bool ArnLink::isThreaded() const
962 {
963  return _mutex != arnNullptr;
964 }
965 
966 
968 void ArnLink::setThreaded()
969 {
970  if (_mutex) return; // Is already threaded
971 
972  ArnLink* link = this;
973  // All links (folders) in direction to root must be threaded due to ArnEvents.
974  do {
975  link->_mutex = new QMutex;
976  link = _parent;
977  } while( link && !link->_mutex);
978 }
979 
980 
981 void ArnLink::lock()
982 {
983  if (_mutex) _mutex->lock();
984 }
985 
986 
987 void ArnLink::unlock()
988 {
989  if (_mutex) _mutex->unlock();
990 }
991 
992 
993 QMutex* ArnLink::getMutex() const
994 {
995  return _mutex;
996 }
997 
998 
999 QObject* ArnLink::arnM( QObject* inArnM)
1000 {
1001  static QObject* storeArnM = arnNullptr;
1002 
1003  if (!storeArnM && inArnM)
1004  storeArnM = inArnM;
1005  return storeArnM;
1006 }
1007 
1008 
1009 bool ArnLink::isRetired()
1010 {
1011  if (_mutex) _mutex->lock();
1012  bool retVal = _isRetired;
1013  if (_mutex) _mutex->unlock();
1014  return retVal;
1015 }
1016 
1017 
1018 uint ArnLink::retireType()
1019 {
1020  if (_mutex) _mutex->lock();
1021  uint retVal = _retireType;
1022  if (_mutex) _mutex->unlock();
1023  return retVal;
1024 }
1025 
1026 
1028 void ArnLink::setRetired( RetireType retireType)
1029 {
1030  if (_mutex) _mutex->lock();
1031  if (Arn::debugLinkDestroy) qDebug() << "setRetired: path=" << this->linkPath();
1032 
1033  _retireType = uint( retireType);
1034  _isRetired = true;
1035 
1036  if (_mutex) _mutex->unlock();
1037 }
1038 
1039 
1040 void ArnLink::doRetired( ArnLink* startLink, bool isGlobal)
1041 {
1042  if (Arn::debugLinkDestroy) qDebug() << "doRetired: path=" << this->linkPath();
1043  if (startLink == this) {
1044  ArnEvRetired arnEvRetired( startLink, true, isGlobal);
1045  sendEventsDirRoot( &arnEvRetired, parent());
1046  }
1047  ArnEvRetired arnEvRetired( startLink, false, isGlobal);
1048  sendArnEvent( &arnEvRetired);
1049 }
1050 
1051 
1052 ArnLink* ArnLink::twinLink()
1053 {
1054  if (_mutex) _mutex->lock();
1055  ArnLink* retVal = _twin;
1056  if (_mutex) _mutex->unlock();
1057  return retVal;
1058 }
1059 
1060 
1061 ArnLink* ArnLink::valueLink()
1062 {
1063  // Mutex not needed, all values are stable
1064  ArnLink* retVal = _isProvider ? _twin : this;
1065  return retVal;
1066 }
1067 
1068 
1069 ArnLink* ArnLink::providerLink()
1070 {
1071  if (_mutex) _mutex->lock();
1072  ArnLink* retVal = _isProvider ? this : _twin;
1073  if (_mutex) _mutex->unlock();
1074  return retVal;
1075 }
1076 
1077 
1078 ArnLink* ArnLink::holderLink( bool useUncrossed)
1079 {
1080  if (_mutex) _mutex->lock();
1081  ArnLink* retVal = (_twin && !useUncrossed) ? _twin : this;
1082  if (_mutex) _mutex->unlock();
1083  return retVal;
1084 }
1085 
1086 
1087 QString ArnLink::twinName()
1088 {
1089  QString linkName = objectName();
1090 
1091  if (isProvider()) { // Link is provider, twin is value
1092  return linkName.left( linkName.size() - 1); // Remove '!' at end
1093  }
1094  else { // Link is value, twin is provider
1095  return linkName + "!";
1096  }
1097 }
1098 
1099 
1101 void ArnLink::setRefCount( int count)
1102 {
1103  ArnLink* vLink = valueLink();
1104 
1105  if (vLink->_mutex) vLink->_mutex->lock();
1106  vLink->_refCount = count;
1107  if (vLink->_mutex) vLink->_mutex->unlock();
1108 }
1109 
1110 
1111 void ArnLink::decZeroRefs()
1112 {
1113  int zeroRefCount = 0;
1114  ArnLink* vLink = valueLink();
1115 
1116  if (vLink->_mutex) vLink->_mutex->lock();
1117  if (vLink->_zeroRefCount > 0) {
1118  vLink->_zeroRefCount--;
1119  zeroRefCount = vLink->_zeroRefCount;
1120  }
1121  if (vLink->_mutex) vLink->_mutex->unlock();
1122  if (Arn::debugLinkRef) qDebug() << "link-decZeroRefs: path=" << this->linkPath()
1123  << " count=" << zeroRefCount;
1124 }
1125 
1126 
1127 bool ArnLink::isLastZeroRef()
1128 {
1129  bool retVal = false;
1130  ArnLink* vLink = valueLink();
1131 
1132  if (vLink->_mutex) vLink->_mutex->lock();
1133  retVal = (vLink->_refCount == 0) && (vLink->_zeroRefCount == 0);
1134  if (vLink->_mutex) vLink->_mutex->unlock();
1135 
1136  return retVal;
1137 }
1138 
1139 
1141 void ArnLink::ref()
1142 {
1143  ArnLink* vLink = valueLink();
1144 
1145  if (vLink->_mutex) vLink->_mutex->lock();
1146  if (vLink->_refCount <= 0) // First reference, no other thread involved
1147  vLink->_refCount = 1;
1148  else
1149  vLink->_refCount++;
1150  if (vLink->_mutex) vLink->_mutex->unlock();
1151  if (Arn::debugLinkRef) qDebug() << "link-ref: path=" << this->linkPath() << " count=" << refCount();
1152 }
1153 
1154 
1155 bool ArnLink::subscribe( ArnCoreItem* subscriber)
1156 {
1157  if (!subscriber) return false; // Not valid subscriber
1158 
1159  if (_mutex) _mutex->lock();
1160  if (!_subscribeTab)
1161  _subscribeTab = new ArnCoreItemList;
1162 
1163  *_subscribeTab += subscriber;
1164  if (_mutex) _mutex->unlock();
1165 
1166  return true; // Subsciber added Ok
1167 }
1168 
1169 
1170 bool ArnLink::unsubscribe( ArnCoreItem* subscriber)
1171 {
1172  if (!subscriber) return false; // Not valid subscriber
1173  if (!_subscribeTab) return false; // Not valid subscribe table
1174 
1175  if (_mutex) _mutex->lock();
1176  bool stat = _subscribeTab->removeOne( subscriber);
1177  if (_mutex) _mutex->unlock();
1178 
1179  return stat;
1180 }
1181 
1182 
1183 void ArnLink::deref()
1184 {
1185  bool isZeroRefs = false;
1186  ArnLink* vLink = valueLink();
1187 
1188  if (vLink->_mutex) vLink->_mutex->lock();
1189  if (vLink->_refCount > 1)
1190  vLink->_refCount--;
1191  else {
1192  vLink->_refCount = 0;
1193  vLink->_zeroRefCount++;
1194  isZeroRefs = true;
1195  }
1196  if (vLink->_mutex) vLink->_mutex->unlock();
1197  if (Arn::debugLinkRef) qDebug() << "link-deref: path=" << this->linkPath() << " count=" << refCount();
1198 
1199  if (isZeroRefs) { // This is last reference
1200  ArnEvZeroRef arnEvZeroRef( this);
1201  sendEventArnM( &arnEvZeroRef); // Will allways be received in main-thread (ArnM)
1203  }
1204 }
1205 
1206 
1207 int ArnLink::refCount()
1208 {
1209  int retVal = 0;
1210  ArnLink* vLink = valueLink();
1211 
1212  if (vLink->_mutex) vLink->_mutex->lock();
1213  retVal = vLink->_refCount;
1214  if (vLink->_mutex) vLink->_mutex->unlock();
1215 
1216  return retVal;
1217 }
1218 
1219 
1220 quint32 ArnLink::localUpdateCount()
1221 {
1222  quint32 retVal = 0;
1223 
1224  if (_mutex) _mutex->lock();
1225  if (_val)
1226  retVal = _val->localUpdateCount;
1227  if (_mutex) _mutex->unlock();
1228 
1229  return retVal;
1230 }
Data type of an Arn Data Object
Definition: Arn.hpp:74
Path: "/@/test" ==> "//test", Item: "@" ==> "".
Definition: Arn.hpp:189
bool debugLinkDestroy
Definition: ArnLib.cpp:40
Implies BiDir and all data is preserved as a stream.
Definition: Arn.hpp:128
Core base class for the inherited ArnItem classes.
Definition: ArnCoreItem.hpp:56
virtual ArnEvent * makeHeapClone()=0
Only on path, no effect on discrete names. "/test/value" ==> "test/value".
Definition: Arn.hpp:191
A two way object, typically for validation or pipe.
Definition: Arn.hpp:126
QThread * thread() const
Get the thread affinity of this ArnCoreItem.
Definition: ArnCoreItem.cpp:69
#define ARNREAL
Definition: Arn.hpp:44
Data is persistent and will be saved.
Definition: Arn.hpp:130
Only on discrete names, no effect on path. "test/" ==> "test".
Definition: Arn.hpp:187
bool debugLinkRef
Definition: ArnLib.cpp:39