Last active
April 27, 2020 23:34
-
-
Save patrickdlogan/444378f56345a66501d8f38c31e75bcc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'dart:collection'; | |
void foo() { | |
Variable fahrenheit; | |
final celsius = | |
Variable.formula(() => ((fahrenheit.get() as double) - 32.0) / 1.8, 0.0); | |
fahrenheit = | |
Variable.formula(() => ((celsius.get() as double) * 1.8) + 32.0, 32.0); | |
print(celsius.get() == 0.0); | |
print(fahrenheit.get() == 32.0); | |
celsius.set(100.0); | |
print(fahrenheit.get() == 212.0); | |
print(celsius.get() == 100.0); | |
fahrenheit.set(-459.67); | |
print(fahrenheit.get() == -459.67); | |
print(celsius.get() == -273.15); | |
} | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Temperature Conversion', | |
debugShowCheckedModeBanner: false, | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: MyHomePage(title: 'Temperature Conversion Home Page'), | |
); | |
} | |
} | |
class MyHomePage extends StatefulWidget { | |
MyHomePage({Key key, this.title}) : super(key: key); | |
final String title; | |
@override | |
_MyHomePageState createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
Variable fahrenheit; | |
Variable celsius; | |
_MyHomePageState() { | |
fahrenheit = | |
Variable.formula(() => ((celsius.get() as double) * 1.8) + 32.0, 32.0); | |
celsius = Variable.formula( | |
() => ((fahrenheit.get() as double) - 32.0) / 1.8, 0.0); | |
} | |
void _incrementCounter() { | |
setState(() { | |
celsius.set((celsius.get() as int) + 1); | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: Text(widget.title), | |
), | |
body: Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
Text( | |
'Celsius:', | |
), | |
Text( | |
'${celsius.get()}', | |
style: Theme.of(context).textTheme.display1, | |
), | |
Text( | |
'Fahrenheit:', | |
), | |
Text( | |
'${(fahrenheit.get() as num).toStringAsFixed(2)}', | |
style: Theme.of(context).textTheme.display1, | |
), | |
], | |
), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: _incrementCounter, | |
tooltip: 'Increment', | |
child: Icon(Icons.add), | |
), | |
); | |
} | |
} | |
class _ConstraintSystem { | |
static final _ConstraintSystem _instance = _ConstraintSystem(); | |
final _demandingVariables = ListQueue<_VariableImpl>(); | |
factory _ConstraintSystem.singleton() => _instance; | |
_ConstraintSystem(); | |
} | |
class _Dependency { | |
final _VariableImpl _variable; | |
int _timestamp = 0; | |
_Dependency(this._variable) { | |
_timestamp = this._variable._timestamp + 1; | |
} | |
} | |
typedef Formula = Object Function(); | |
abstract class Variable { | |
Variable(); | |
factory Variable.value(Object value) => _VariableImpl.value(value); | |
factory Variable.formula(Formula formula, Object value) => | |
_VariableImpl.formula(formula, value); | |
/// Get the value of the variable. Out-of-date formulas are updated if necessary. | |
Object get(); | |
void set(Object value); | |
Type get valueType; | |
int get length => 1; | |
} | |
/// A variable that can maintain a value that depends on other variables including cyclic dependencies. | |
class _VariableImpl extends Variable { | |
Object _value; | |
Formula _formula; | |
int _timestamp = 0; | |
bool _outOfDate = false; | |
final _dependents = <_Dependency>[]; | |
_VariableImpl() { | |
_value = null; | |
} | |
/// Construct a Variable whose value is explicit and is not a formula that depends on any other Variable. | |
_VariableImpl.value(this._value); | |
// Construct a Variable whose value is computed by a formula, is initially out of date, with cyclical dependencies initially resolved by the given value. | |
_VariableImpl.formula(this._formula, this._value) { | |
_outOfDate = true; | |
} | |
/// Get the value of the variable, computing the formula if it is out of date, with cyclical dependencies resolved using the current value. | |
@override | |
Object get() { | |
final system = _ConstraintSystem.singleton(); | |
if (system._demandingVariables.isNotEmpty) { | |
final demandingVariable = system._demandingVariables.first; | |
final dep = _dependents.firstWhere( | |
(dep) => dep._variable == demandingVariable, | |
orElse: () => null); | |
if (dep == null) { | |
_dependents.add(_Dependency(demandingVariable)); | |
} else { | |
dep._timestamp = demandingVariable._timestamp + 1; | |
} | |
} | |
if (_outOfDate) { | |
system._demandingVariables.addFirst(this); | |
_outOfDate = false; | |
_value = _formula(); | |
_timestamp++; | |
system._demandingVariables.removeFirst(); | |
} | |
return _value; | |
} | |
/// Assign to the variable an explicit value that is not a formula, marking any dependents out of date. | |
@override | |
void set(Object value) { | |
_value = value; | |
_mark(<Variable>[]); | |
// Explicit values are not computed and so are never out of date. | |
_outOfDate = false; | |
} | |
/// Mark the variable and all dependents of the variable out of date, placing the dependents in a queue. | |
void _mark(List<Variable> marked) { | |
if (marked.contains(this)) return; | |
marked.add(this); | |
_outOfDate = | |
true; // A Variable associated with a stateful Flutter widget would set the state changed here. | |
final removals = <_Dependency>[]; | |
_dependents.forEach((dep) { | |
if (dep._timestamp < dep._variable._timestamp) { | |
removals.add(dep); | |
} else if (!dep._variable._outOfDate) { | |
dep._variable._mark(marked); | |
} | |
}); | |
marked.remove(this); | |
removals.forEach((dep) { | |
_dependents.remove(dep); | |
}); | |
} | |
@override | |
Type get valueType => (_outOfDate) ? Formula : _value.runtimeType; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment