I'm building a bunch of Uint8List (of different sizes, for now they are stored in a generic List) and I need to combine/concatenate them before sending on a websocket.
What would be the best approach ?
I though of combining them in a new Uint8List, but since I don't need byte access anymore after it is combined, I can maybe use a different List<int> implementation ... ?
Thanks in advance.
Using BytesBuilder seems to be the most efficient way to concatenate Uint8List's in Dart:
var b = BytesBuilder();
var l1 = Uint8List(4);
var l2 = Uint8List(4);
b.add(l1);
b.add(l2);
var ll = b.toBytes();
Uint8List implements List<int>. You can combine them to a new List<int> and then create a new Uint8List with
List<List<int>> myByteLists = ...;
var bytes = Uint8List.fromList(myByteList.expand((x) => x).toList());
Related
Is there any way to compare two times in dart, suppose we have: 13:45 and 15:34, is there any way to find out that 15:34 is after 13:45.
I was looking at this question, and there are functions to check isBefore or isAfter, but is it possible to parse time without having to parse year, month and day?
You can convert them to datetime and compare. ie:
void main() {
var s1 = '13:45';
var s2 = '15:34';
var t1 = DateTime.parse('2000-01-01 ${s1}');
var t2 = DateTime.parse('2000-01-01 ${s2}');
print(t1.isBefore(t2));
}
EDIT: For a more direct, string sort like comparison (which I wouldn't suggest at all for Date\time values, unless you are 100% sure they are in sortable format) you could use compareTo(). ie:
print(s1.compareTo(s2) < 0);
Assume I want to concatenate N Uint8Lists into a single one.
The naive approach is to simple copy all elements into a new list. However, that seems rather memory in efficient. Instead, I want to create a single Uint8List "view" which simply indexes into the appropriate underlying list instead of copying all its content.
In C++ I'd usually just overwrite operator[] but I am not quite certain how to do this with Uint8Lists in Dart.
In C++, you can make a View class that overrides operator[]. In Dart, you could do the same thing:
class View<T> {
View(this._lists);
List<List<T>> _lists;
T operator [](int index) {
for (var list in _lists) {
if (index < list.length) {
return list[index];
}
index -= list.length;
}
throw RangeError('...');
}
}
You could stop there, but doing just that usually wouldn't be enough in either language. In C++, you'd also want to provide begin() and end() methods for range-based for loops to work. Similarly, in Dart, you'd want to provide the Iterable interface so that for-in would work.
Luckily package:collection (note that this is separate from dart:collection) provides a CombinedListView class that does that work for you. For example:
import 'dart:typed_data';
import 'package:collection/collection.dart';
void main() {
var list1 = Uint8List.fromList([1, 2, 3]);
var list2 = Uint8List.fromList([4, 5, 6]);
var list3 = Uint8List.fromList([7, 8, 9]);
var view = CombinedListView<int>([list1, list2, list3]);
for (var i in view) {
print(i);
}
}
I have a Map literal, an I want it to be a TreeMap, but by default I believe it's a LinkedHashMap. Casting a LinkedHashMap to a TreeMap won't work as it's not a subtype.
Basically, I'm looking for the simplest way to make this work:
var map = <int, int>{for(int i = 0; i < intervals.length; i++) intervals[i][0] : i} as SplayTreeMap;
As mentioned before, casting as SplayTreeMap won't work as they types don't align.
Thanks much in advance
Use the SplayTreeMap.from constructor to create a SplayTreeMap. There isn't any way to cast it as you said.
Remove the as from your current code and add this to get your SplayTreeMap:
var newMap = SplayTreeMap.from(map);
Depending on your key type and your use case, you can pass compare and isValidKey parameters as well. Full constructor definition:
SplayTreeMap<K, V>.from(
Map other,
[int compare(
K key1,
K key2
),
bool isValidKey(
dynamic potentialKey
)]
)
I was wondering if there is way of converting lists with complex numbers into list with real numbers.
[3.084580633850594 + 0.0i, 0.03930937672422563 + 0.0i, 25958.26505623091 + 0.0i, 28566.521479745476 + 0.0i]
The way in which i did it was by using.
for (var item in list){
double real = item.real;
}
https://pub.dartlang.org/documentation/my_complex/latest/my_complex/Complex/real.html
If you have an existing list of complex numbers using some appropriate Complex number class, using List.map would be neater:
var realParts = complexNumbers.map((z) => z.real);
Note that that will give you an Iterable; if you want a List, you'll need to call Iterable.toList:
var realParts = complexNumbers.map((z) => z.real).toList();
I am trying to use a HashMap of Lists of strings in Vala, but it seems the object lifecycle is biting me. Here is my current code:
public class MyClass : CodeVisitor {
GLib.HashTable<string, GLib.List<string>> generic_classes = new GLib.HashTable<string, GLib.List<string>> (str_hash, str_equal);
public override void visit_data_type(DataType d) {
string c = ...
string s = ...
if (! this.generic_classes.contains(c)) {
this.generic_classes.insert(c, new GLib.List<string>());
}
unowned GLib.List<string> l = this.generic_classes.lookup(c);
bool is_dup = false;
foreach(unowned string ss in l) {
if (s == ss) {
is_dup = true;
}
}
if ( ! is_dup) {
l.append(s);
}
}
Note that I am adding a string value into the list associated with a string key. If the list doesn't exist, I create it.
Lets say I run the code with the same values of c and s three times. Based some printf debugging, it seems that only one list is created, yet each time it is empty. I'd expect the list of have size 0, then 1, and then 1. Am I doing something wrong when it comes to the Vala memory management/reference counting?
GLib.List is the problem here. Most operations on GLib.List and GLib.SList return a modified pointer, but the value in the hash table isn't modified. It's a bit hard to explain why that is a problem, and why GLib works that way, without diving down into the C. You have a few choices here.
Use one of the containers in libgee which support multiple values with the same key, like Gee.MultiMap. If you're working on something in the Vala compiler (which I'm guessing you are, as you're subclassing CodeVisitor), this isn't an option because the internal copy of gee Vala ships with doesn't include MultiMap.
Replace the GLib.List instances in the hash table. Unfortunately this is likely going to mean copying the whole list every time, and even then getting the memory management right would be a bit tricky, so I would avoid it if I were you.
Use something other than GLib.List. This is the way I would go if I were you.
Edit: I recently added GLib.GenericSet to Vala as an alternative binding for GHashTable, so the best solution now would be to use GLib.HashTable<string, GLib.GenericSet<string>>, assuming you're okay with depending on vala >= 0.26.
If I were you, I would use GLib.HashTable<string, GLib.HashTable<unowned string, string>>:
private static int main (string[] args) {
GLib.HashTable<string, GLib.HashTable<unowned string, string>> generic_classes =
new GLib.HashTable<string, GLib.HashTable<unowned string, string>> (GLib.str_hash, GLib.str_equal);
for (int i = 0 ; i < 3 ; i++) {
string c = "foo";
string s = i.to_string ();
unowned GLib.HashTable<unowned string, string>? inner_set = generic_classes[c];
stdout.printf ("Inserting <%s, %s>, ", c, s);
if (inner_set == null) {
var v = new GLib.HashTable<unowned string, string> (GLib.str_hash, GLib.str_equal);
inner_set = v;
generic_classes.insert ((owned) c, (owned) v);
}
inner_set.insert (s, (owned) s);
stdout.printf ("container now holds:\n");
generic_classes.foreach ((k, v) => {
stdout.printf ("\t%s:\n", k);
v.foreach ((ik, iv) => {
stdout.printf ("\t\t%s\n", iv);
});
});
}
return 0;
}
It may seem hackish to have a hash table with the key and value having the same value, but this is actually a common pattern in C as well, and specifically supported by GLib's hash table implementation.
Moral of the story: don't use GLib.List or GLib.SList unless you really know what you're doing, and even then it's generally best to avoid them. TBH we probably would have marked them as deprecated in Vala long ago if it weren't for the fact that they're very common when working with C APIs.
Vala's new can be a little weird when used as a parameter. I would recommend assigning the new list to a temporary, adding it to the list, then letting it go out of scope.
I would also recommend using libgee. It has better handling of generics than GLib.List and GLib.HashTable.