]> git.tdb.fi Git - libs/gltk.git/blobdiff - source/layout.cpp
Use std::unique_ptr for managing memory
[libs/gltk.git] / source / layout.cpp
index 7fcbf103b085808fe34fa0d45f67b54fd5442251..495d6261c6483b55f3f76bee50b7980eb0fd33a1 100644 (file)
@@ -19,44 +19,44 @@ public:
        {
        private:
                LinearProgram &linprog;
-               unsigned index;
+               size_t index;
 
        public:
-               Row(LinearProgram &, unsigned);
+               Row(LinearProgram &, size_t);
 
-               float &operator[](unsigned);
+               float &operator[](size_t);
                float &back();
        };
 
 private:
        struct Column
        {
-               unsigned basic;
+               size_t basic;
                std::vector<float> values;
 
                Column();
        };
 
-       unsigned n_columns = 1;
-       unsigned n_rows = 1;
+       size_t n_columns = 1;
+       size_t n_rows = 1;
        std::vector<Column> columns;
        bool solved = false;
        bool infeasible = false;
 
 public:
-       LinearProgram(unsigned);
+       LinearProgram(size_t);
 
        Row add_row();
-       Row operator[](unsigned);
+       Row operator[](size_t);
        Row get_objective_row();
-       float get_variable(unsigned);
+       float get_variable(size_t);
        bool solve();
 private:
        void prepare_columns();
        void add_artificial_variables();
        void remove_artificial_variables();
-       unsigned find_minimal_ratio(unsigned);
-       void make_basic_column(unsigned, unsigned);
+       size_t find_minimal_ratio(size_t);
+       void make_basic_column(size_t, size_t);
        bool pivot();
 };
 
@@ -85,12 +85,6 @@ Layout::Pointers Layout::pointers[2] =
 } };
 
 
-Layout::~Layout()
-{
-       for(Slot *s: slots)
-               delete s;
-}
-
 void Layout::set_container(Container &c)
 {
        if(container)
@@ -163,7 +157,7 @@ void Layout::add_widget(Widget &wdg)
        if(!container)
                throw logic_error("!container");
 
-       slots.push_back(new Slot(*this, wdg));
+       slots.emplace_back(make_unique<Slot>(*this, wdg));
        update_slot_indices();
        if(!arrangement_stack.empty())
                arrangement_stack.back()->arrange(wdg);
@@ -173,23 +167,22 @@ void Layout::add_widget(Widget &wdg)
 
 void Layout::remove_widget(Widget &wdg)
 {
-       auto i = find_if(slots, [&wdg](Slot *s){ return &s->widget==&wdg; });
+       auto i = find_if(slots, [&wdg](const unique_ptr<Slot> &s){ return &s->widget==&wdg; });
        if(i==slots.end())
                return;
 
-       for(Slot *s: slots)
+       for(const unique_ptr<Slot> &s: slots)
                if(s!=*i)
                {
                        for(auto k=s->constraints.begin(); k!=s->constraints.end(); )
                        {
-                               if(&k->target==*i)
-                                       s->constraints.erase(k++);
+                               if(k->target==i->get())
+                                       k = s->constraints.erase(k);
                                else
                                        ++k;
                        }
                }
 
-       delete *i;
        slots.erase(i);
 
        update_slot_indices();
@@ -199,8 +192,8 @@ void Layout::remove_widget(Widget &wdg)
 void Layout::update_slot_indices()
 {
        n_active_slots = 0;
-       unsigned n_floating = 0;
-       for(Slot *s: slots)
+       size_t n_floating = 0;
+       for(const unique_ptr<Slot> &s: slots)
        {
                if(s->widget.is_visible() || s->ghost)
                {
@@ -214,25 +207,25 @@ void Layout::update_slot_indices()
 
        n_slack_vars[0] = n_floating*2;
        n_slack_vars[1] = n_floating*2;
-       for(const Slot *s: slots)
+       for(const unique_ptr<Slot> &s: slots)
                if(s->index>=0)
                {
                        if(!s->floating)
                        {
                                for(unsigned j=0; j<2; ++j)
-                                       if((s->*(pointers[j].packing)).gravity==0)
+                                       if((s.get()->*(pointers[j].packing)).gravity==0)
                                                n_slack_vars[j] += 2;
                        }
 
                        for(const Constraint &c: s->constraints)
-                               if(c.target.index>s->index && (c.type&SLACK))
+                               if(c.target->index>s->index && (c.type&SLACK))
                                        ++n_slack_vars[c.type&1];
                }
 }
 
 Layout::Slot &Layout::get_slot_for_widget(Widget &wdg)
 {
-       auto i = find_if(slots, [&wdg](const Slot *s){ return &s->widget==&wdg; });
+       auto i = find_if(slots, [&wdg](const unique_ptr<Slot> &s){ return &s->widget==&wdg; });
        if(i==slots.end())
                throw hierarchy_error("widget not in layout");
 
@@ -253,7 +246,7 @@ void Layout::create_constraint(Widget &src, ConstraintType type, Widget &tgt, in
        Slot &tgt_slot = get_slot_for_widget(tgt);
 
        for(const Constraint &c: src_slot.constraints)
-               if(c.type==type && &c.target==&tgt_slot)
+               if(c.type==type && c.target==&tgt_slot)
                        return;
 
        src_slot.constraints.push_back(Constraint(type, tgt_slot));
@@ -324,7 +317,7 @@ void Layout::update()
        solve_constraints(HORIZONTAL, UPDATE);
        solve_constraints(VERTICAL, UPDATE);
 
-       for(const Slot *s: slots)
+       for(const unique_ptr<Slot> &s: slots)
                s->widget.set_geometry(s->geom);
 }
 
@@ -351,8 +344,8 @@ void Layout::solve_constraints(int dir, SolveMode mode)
        remaining three are slack columns; see below for their purposes. */
        LinearProgram linprog(n_active_slots*5+n_slack_vars[dir]+1);
        float weight = slots.size()+1;
-       unsigned k = n_active_slots*5;
-       for(const Slot *s: slots)
+       size_t k = n_active_slots*5;
+       for(const unique_ptr<Slot> &s: slots)
        {
                if(s->index<0)
                        continue;
@@ -366,8 +359,8 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                else
                {
                        if(!s->floating)
-                               objective[s->index*5] = (s->*(ptrs.packing)).gravity/weight;
-                       objective[s->index*5+1] = ((s->*(ptrs.packing)).expand ? weight : -1);
+                               objective[s->index*5] = (s.get()->*(ptrs.packing)).gravity/weight;
+                       objective[s->index*5+1] = ((s.get()->*(ptrs.packing)).expand ? weight : -1);
                }
 
                {
@@ -388,12 +381,12 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                        row.back() = geom.*(ptrs.dim)-margin.*(ptrs.high_margin);
                }
 
-               if(s->floating || (s->*(ptrs.packing)).gravity==0)
+               if(s->floating || (s.get()->*(ptrs.packing)).gravity==0)
                {
                        /* Try to keep the widget as close to a target position as possible.
                        Since linear programs can't express absolute values directly, use two
                        opposing slack variables that are optimized for a low value. */
-                       float a = (s->*(ptrs.packing)).gravity*0.5+0.5;
+                       float a = (s.get()->*(ptrs.packing)).gravity*0.5+0.5;
                        LinearProgram::Row row = linprog.add_row();
                        row[s->index*5] = 1;
                        row[s->index*5+1] = a;
@@ -423,7 +416,7 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                /* Add rows for user-defined constraints.  Constraints are always added
                in pairs, so it's only necessary to create a row for one half. */
                for(const Constraint &c: s->constraints)
-                       if(c.target.index>s->index && (c.type&1)==dir)
+                       if(c.target->index>s->index && (c.type&1)==dir)
                        {
                                LinearProgram::Row row = linprog.add_row();
                                float polarity = ((c.type&SELF_DIM) ? -1 : 1);
@@ -433,9 +426,9 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                                if(c.type&SELF_DIM)
                                        row[s->index*5+1] = polarity*dim_weight;
                                if(c.type&TARGET_POS)
-                                       row[c.target.index*5] = -polarity;
+                                       row[c.target->index*5] = -polarity;
                                if(c.type&TARGET_DIM)
-                                       row[c.target.index*5+1] = -polarity*dim_weight;
+                                       row[c.target->index*5+1] = -polarity*dim_weight;
                                if(c.type&SPACING)
                                        row.back() = (c.spacing>=0 ? c.spacing : this->*(ptrs.spacing));
                                if(c.type&SLACK)
@@ -449,7 +442,7 @@ void Layout::solve_constraints(int dir, SolveMode mode)
        if(mode==AUTOSIZE)
        {
                autosize_geom.*(ptrs.dim) = 0;
-               for(const Slot *s: slots)
+               for(const unique_ptr<Slot> &s: slots)
                        if(s->index>=0)
                        {
                                int high_edge = linprog.get_variable(s->index*5)+linprog.get_variable(s->index*5+1);
@@ -458,7 +451,7 @@ void Layout::solve_constraints(int dir, SolveMode mode)
        }
        else
        {
-               for(Slot *s: slots)
+               for(const unique_ptr<Slot> &s: slots)
                        if(s->index>=0)
                        {
                                s->geom.*(ptrs.pos) = linprog.get_variable(s->index*5);
@@ -470,7 +463,7 @@ void Layout::solve_constraints(int dir, SolveMode mode)
 
 Layout::Constraint::Constraint(ConstraintType t, Slot &s):
        type(t),
-       target(s)
+       target(&s)
 { }
 
 
@@ -624,7 +617,7 @@ void operator>>(const LexicalConverter &conv, Layout::ConstraintType &ctype)
 }
 
 
-Layout::LinearProgram::LinearProgram(unsigned s):
+Layout::LinearProgram::LinearProgram(size_t s):
        n_columns(s),
        columns(n_columns)
 { }
@@ -634,7 +627,7 @@ Layout::LinearProgram::Row Layout::LinearProgram::add_row()
        return Row(*this, n_rows++);
 }
 
-Layout::LinearProgram::Row Layout::LinearProgram::operator[](unsigned r)
+Layout::LinearProgram::Row Layout::LinearProgram::operator[](size_t r)
 {
        if(r>=n_rows)
                throw out_of_range("LinearProgram::operator[]");
@@ -647,14 +640,14 @@ Layout::LinearProgram::Row Layout::LinearProgram::get_objective_row()
        return Row(*this, 0);
 }
 
-float Layout::LinearProgram::get_variable(unsigned i)
+float Layout::LinearProgram::get_variable(size_t i)
 {
        if(!solved || infeasible)
                throw logic_error("not solved");
        if(i+1>=n_columns)
                throw out_of_range("LinearProgram::get_variable");
 
-       if(unsigned r = columns[i].basic)
+       if(size_t r = columns[i].basic)
                return columns.back().values[r];
        else
                return 0;
@@ -707,7 +700,7 @@ void Layout::LinearProgram::prepare_columns()
                if(c.values.size()>=2 && c.values.back()!=0.0f && (constants.size()<c.values.size() || c.values.back()*constants[c.values.size()-1]>=0.0f) && obj_coeff[c.values.size()-1]==0.0f)
                {
                        bool basic = true;
-                       for(unsigned j=1; (basic && j+1<c.values.size()); ++j)
+                       for(size_t j=1; (basic && j+1<c.values.size()); ++j)
                                basic = (c.values[j]==0.0f);
                        if(basic)
                        {
@@ -722,7 +715,7 @@ void Layout::LinearProgram::prepare_columns()
        for(Column &c: columns)
                if(!c.values.empty())
                {
-                       for(unsigned j=0; j<c.values.size(); ++j)
+                       for(size_t j=0; j<c.values.size(); ++j)
                        {
                                c.values[j] *= row_coeff[j];
                                c.values.front() += obj_coeff[j]*c.values[j];
@@ -732,8 +725,8 @@ void Layout::LinearProgram::prepare_columns()
 
 void Layout::LinearProgram::add_artificial_variables()
 {
-       vector<unsigned> artificial_rows(n_rows-1);
-       for(unsigned i=0; i<artificial_rows.size(); ++i)
+       vector<size_t> artificial_rows(n_rows-1);
+       for(size_t i=0; i<artificial_rows.size(); ++i)
                artificial_rows[i] = i+1;
 
        for(const Column &c: columns)
@@ -752,7 +745,7 @@ void Layout::LinearProgram::add_artificial_variables()
                        {
                                objective = c.values.front();
                                c.values.front() = 0.0f;
-                               for(unsigned r: artificial_rows)
+                               for(size_t r: artificial_rows)
                                        if(r<c.values.size())
                                                c.values.front() += c.values[r];
                        }
@@ -769,7 +762,7 @@ void Layout::LinearProgram::add_artificial_variables()
        columns.resize(n_columns+artificial_rows.size());
        columns.back() = columns[n_columns-1];
        columns[n_columns-1].values.clear();
-       for(unsigned i=0; i<artificial_rows.size(); ++i)
+       for(size_t i=0; i<artificial_rows.size(); ++i)
                columns[n_columns+i-1].basic = artificial_rows[i];
 }
 
@@ -780,10 +773,10 @@ void Layout::LinearProgram::remove_artificial_variables()
        some of the original variables basic instead.
 
        I don't fully understand why this is needed, but it appears to work. */
-       for(unsigned i=n_columns-1; i+1<columns.size(); ++i)
+       for(size_t i=n_columns-1; i+1<columns.size(); ++i)
                if(columns[i].basic && columns.back().values[columns[i].basic]==0.0f)
                {
-                       for(unsigned j=0; j+1<n_columns; ++j)
+                       for(size_t j=0; j+1<n_columns; ++j)
                                if(!columns[j].basic && columns[j].values[columns[i].basic]!=0.0f)
                                {
                                        make_basic_column(j, columns[i].basic);
@@ -802,7 +795,7 @@ void Layout::LinearProgram::remove_artificial_variables()
                }
 }
 
-unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c)
+size_t Layout::LinearProgram::find_minimal_ratio(size_t c)
 {
        /* Pick the row with the minimum ratio between the constant column and the
        pivot column.  This ensures that when the pivot column is made basic, values
@@ -811,8 +804,8 @@ unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c)
        The use of n_rows instead of the true size of the column is intentional,
        since the relocated objective row must be ignored in phase 1. */
        float best = numeric_limits<float>::infinity();
-       unsigned row = 0;
-       for(unsigned i=1; i<n_rows; ++i)
+       size_t row = 0;
+       for(size_t i=1; i<n_rows; ++i)
                if(columns[c].values[i]>0)
                {
                        float ratio = columns.back().values[i]/columns[c].values[i];
@@ -826,11 +819,11 @@ unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c)
        return row;
 }
 
-void Layout::LinearProgram::make_basic_column(unsigned c, unsigned r)
+void Layout::LinearProgram::make_basic_column(size_t c, size_t r)
 {
        /* Perform row transfer operations to make the pivot column basic,
        containing a 1 on the pivot row. */
-       for(unsigned i=0; i<columns.size(); ++i)
+       for(size_t i=0; i<columns.size(); ++i)
                if(i!=c && (columns[i].basic==r || (!columns[i].basic && columns[i].values[r])))
                {
                        if(columns[i].basic)
@@ -843,7 +836,7 @@ void Layout::LinearProgram::make_basic_column(unsigned c, unsigned r)
                        float scale = columns[i].values[r]/columns[c].values[r];
 
                        columns[i].values[r] = scale;
-                       for(unsigned j=0; j<columns[i].values.size(); ++j)
+                       for(size_t j=0; j<columns[i].values.size(); ++j)
                                if(j!=r)
                                        columns[i].values[j] -= scale*columns[c].values[j];
                }
@@ -857,9 +850,9 @@ bool Layout::LinearProgram::pivot()
        /* Pick a nonbasic column and make it basic.  Requiring a positive objective
        coefficient ensures that the objective function's value will decrease in the
        process. */
-       for(unsigned i=0; i+1<columns.size(); ++i)
+       for(size_t i=0; i+1<columns.size(); ++i)
                if(!columns[i].basic && columns[i].values.front()>0)
-                       if(unsigned row = find_minimal_ratio(i))
+                       if(size_t row = find_minimal_ratio(i))
                        {
                                make_basic_column(i, row);
                                return true;
@@ -869,12 +862,12 @@ bool Layout::LinearProgram::pivot()
 }
 
 
-Layout::LinearProgram::Row::Row(LinearProgram &lp, unsigned i):
+Layout::LinearProgram::Row::Row(LinearProgram &lp, size_t i):
        linprog(lp),
        index(i)
 { }
 
-float &Layout::LinearProgram::Row::operator[](unsigned c)
+float &Layout::LinearProgram::Row::operator[](size_t c)
 {
        if(c>=linprog.n_columns)
                throw out_of_range("Row::operator[]");