Coverage Report

Created: 2025-08-24 07:05

/src/openbabel/src/ops/deferred.h
Line
Count
Source (jump to first uncovered line)
1
#include <openbabel/babelconfig.h>
2
#include <openbabel/op.h>
3
#include <openbabel/obconversion.h>
4
#include <vector>
5
#include <algorithm>
6
7
namespace OpenBabel
8
{
9
/**
10
DeferredFormat class is intended to assist writing ops that influence the
11
conversion of multiple molecules with the OBConversion Convert interface.
12
See, for instance, OpSort. Although it is a format, it does not registered
13
itself, an object is not constructed in ReadChemObject() or deleted in
14
WriteChemObject(). It is used in a different way from normal formats. An 
15
op makes an instance of DeferredFormat, probably when it is first called
16
in its Do() function.
17
\code
18
  if(pConv && pConv->IsFirstInput())
19
    new DeferredFormat(pConv, this); //it will delete itself
20
\endcode
21
Output objects (probably molecules) will then all be diverted to the
22
DeferredFormat instance and pointers to them stored there. After the last
23
object, it calls the op's ProcessVec(std::vector<OBBase*>& vec) function.
24
The objects can be manipulated or deleted (call delete with their pointer).
25
When the function returns, the remaining molecules in the vector will be
26
output to the normal output format. No conversion options are applied at
27
this stage, since they already have been earlier.
28
29
Constructing with a third boolean parameter set true allows an alternative mode
30
of operation. Before storing the pointer to an object, DeferredFormat calls
31
the op's Do() function and stores the object pointer only if this returns true.
32
This has the effect of allowing the op to act after all the other options,
33
rather than before most of them. See OpLargest for an example.
34
**/
35
class DeferredFormat : public OBFormat
36
{
37
public:
38
  DeferredFormat(OBConversion* pConv, OBOp* pOp=nullptr, bool CallDo=false)
39
0
  {
40
0
    _pRealOutFormat = pConv->GetOutFormat();
41
0
    pConv->SetOutFormat(this);
42
0
    _pOp = pOp;
43
0
    _callDo = CallDo;
44
0
  }
45
0
  const char* Description() override { return "Read and write an OBBase* array"; }
46
47
  bool ReadChemObject(OBConversion* pConv) override
48
0
  {
49
0
    if(_obvec.empty())
50
0
    {
51
0
      delete this;//self destruction; was made in new in an OBOp
52
0
      return false;
53
0
    }
54
    //returned in reverse order, because its easier with a vector
55
0
    pConv->AddChemObject(_obvec.back());
56
0
    _obvec.pop_back();
57
0
    return true;
58
0
  }
59
60
  bool WriteChemObject(OBConversion* pConv) override
61
0
  {
62
0
    OBBase* pOb = pConv->GetChemObject();
63
0
    if(!_callDo || _pOp->Do(pOb, "", pConv->GetOptions(OBConversion::GENOPTIONS), pConv))  
64
0
      _obvec.push_back(pOb); // Store the object pointer.
65
66
0
    if(pConv->IsLast())
67
0
    {
68
      //At the end, sort, or whatever, the vector
69
0
      if(_pOp)
70
0
      {
71
        //clear the options if return is true - they have already been applied
72
0
        if(_pOp->ProcessVec(_obvec))
73
0
          pConv->SetOptions("",OBConversion::GENOPTIONS);
74
75
        //Now output the processed vector, unless it is empty
76
0
        if(!_obvec.empty())
77
0
        {
78
0
          std::reverse(_obvec.begin(),_obvec.end()); //because DeferredFormat outputs in reverse order
79
0
          pConv->SetInAndOutFormats(this, _pRealOutFormat);
80
81
0
          std::ifstream ifs; // get rid of gcc warning
82
0
          pConv->SetInStream(&ifs);//Not used, but Convert checks it is ok
83
0
          pConv->GetInStream()->clear();
84
85
0
          pConv->SetOutputIndex(0);
86
0
          pConv->Convert();
87
0
        }
88
0
      }
89
0
    }
90
0
    return true;
91
0
  }
92
private:
93
  OBFormat* _pRealOutFormat;
94
  std::vector<OBBase*> _obvec;
95
  public:
96
  OBOp* _pOp;
97
  bool _callDo;
98
};
99
100
} //namespace
101