Main optimization entry point. Pass in a list of Operation instances, get out a new list of Operation instances. Unfortunately, due to the scope of the optimization (two combinable operations might be separated by several hundred others), this can't be done
(self, operations, app_label)
| 10 | """ |
| 11 | |
| 12 | def optimize(self, operations, app_label): |
| 13 | """ |
| 14 | Main optimization entry point. Pass in a list of Operation instances, |
| 15 | get out a new list of Operation instances. |
| 16 | |
| 17 | Unfortunately, due to the scope of the optimization (two combinable |
| 18 | operations might be separated by several hundred others), this can't be |
| 19 | done as a peephole optimization with checks/output implemented on |
| 20 | the Operations themselves; instead, the optimizer looks at each |
| 21 | individual operation and scans forwards in the list to see if there |
| 22 | are any matches, stopping at boundaries - operations which can't |
| 23 | be optimized over (RunSQL, operations on the same field/model, etc.) |
| 24 | |
| 25 | The inner loop is run until the starting list is the same as the result |
| 26 | list, and then the result is returned. This means that operation |
| 27 | optimization must be stable and always return an equal or shorter list. |
| 28 | """ |
| 29 | # Internal tracking variable for test assertions about # of loops |
| 30 | if app_label is None: |
| 31 | raise TypeError("app_label must be a str.") |
| 32 | self._iterations = 0 |
| 33 | while True: |
| 34 | result = self.optimize_inner(operations, app_label) |
| 35 | self._iterations += 1 |
| 36 | if result == operations: |
| 37 | return result |
| 38 | operations = result |
| 39 | |
| 40 | def optimize_inner(self, operations, app_label): |
| 41 | """Inner optimization loop.""" |