1/* { dg-do compile } */
2/* { dg-options "-O2 -ftree-tail-merge" } */
3typedef int BoxCoordinate;
4typedef int BoxDimension;
5const BoxDimension X = 0;
6const BoxDimension Y = 1;
7const BoxDimension NDimensions = 2;
8class BoxPoint {
9    BoxCoordinate point[NDimensions];
10public:
11    bool isValid() const;
12    void operator += (const BoxPoint& p)     {
13        if (isValid() && p.isValid())  {
14            point[X] += p.point[X];
15        }
16    }
17    const BoxCoordinate& operator [] (const BoxDimension& dimension) const {
18        return point[dimension];
19    }
20};
21class BoxRegion {
22public:
23    BoxCoordinate& origin(BoxDimension d) const;
24    BoxCoordinate& space(BoxDimension d) const;
25};
26inline bool operator <= (const BoxPoint& p, const BoxRegion& r) {
27    for (BoxDimension d = X;
28         d <= Y;
29         d++)  if (p[d] < r.origin(d) || p[d] >= r.origin(d) + r.space(d))
30return false;
31    return true;
32}
33typedef struct _WidgetRec *Widget;
34struct GraphGC {
35    BoxPoint offsetIfSelected;
36};
37class GraphNode;
38class GraphEdge {
39public:
40    GraphNode *from() const;
41    GraphNode *to() const;
42};
43class LineGraphEdge: public GraphEdge {
44protected:
45    virtual void drawLine(Widget w,      const GraphGC& gc) const;
46    void _print(const GraphGC &gc) const;
47};
48class ArcGraphEdge: public LineGraphEdge {
49    static bool center(const BoxPoint& p1, const BoxPoint& p2,
50                       const BoxPoint& p3, double& x, double& y);
51    void makeLine(Widget w,     const GraphGC& gc) const;
52};
53class GraphNode {
54public:
55    bool& selected();
56    GraphEdge *firstTo() const;
57    GraphEdge *nextTo(GraphEdge *ref) const;
58    virtual const BoxPoint& pos() const = 0;
59    virtual const BoxRegion& region(const GraphGC& gc) const = 0;
60    virtual bool isHint() const;
61};
62class PosGraphNode: public GraphNode { };
63class RegionGraphNode: public PosGraphNode { };
64class HintGraphNode: public RegionGraphNode { };
65void ArcGraphEdge::makeLine(Widget w, const GraphGC& gc) const {
66    HintGraphNode *arc_hint = 0;
67    RegionGraphNode *arc_from = 0;
68    RegionGraphNode *arc_to = 0;
69    bool make_arc = true;
70    if (from()->isHint() && to()->isHint())     {
71        make_arc = false;
72    }
73    else if (from()->isHint() && from()->firstTo() != 0)     {
74        if (arc_hint == 0 || arc_from == 0 || arc_to == 0
75            || arc_hint->nextTo(arc_hint->firstTo()) != 0)  {
76            make_arc = false;
77        }
78    }
79    if (!make_arc)     {
80        if (w != 0)      LineGraphEdge::drawLine(w, gc);
81        else      LineGraphEdge::_print(gc);
82        return;
83    }
84    BoxPoint pos_from = arc_from->pos();
85    BoxRegion region_from = arc_from->region(gc);
86    BoxPoint pos_to = arc_to->pos();
87    BoxRegion region_to = arc_to->region(gc);
88    BoxPoint pos_hint = arc_hint->pos();
89    if (arc_hint->selected())     {
90        pos_hint += gc.offsetIfSelected;
91    }
92    if (pos_hint <= region_from || pos_hint <= region_to)     {
93        return;
94    }
95    double cx, cy;
96    bool ok = center(pos_from, pos_hint, pos_to, cx, cy);
97    if (!ok)     {
98        if (w != 0)      LineGraphEdge::drawLine(w, gc);
99        else      LineGraphEdge::_print(gc);
100    }
101}
102