Encoding vector length field not adjacent to the vector - scodec

I have the following structure I like to encode.
I'm aware that I can encode a vector with vector() if the size field is directly in front of the vector data. But here the field encoding the vector size is not adjacent.
case class Item(
address: Int,
size: Int,
)
case class Header {
// lots of other fields before
numOfItems: Int,
// lots of other fields after
}
case class Outer(
hdr: Header,
items: Vector[]
)
Decoding of Outer is OK:
Header.numOfItems is read from the bit vector and items is created with vectorOfN(provide(hdr.numOfItems, Item.codec))
Encoding of Outer is the problem:
When encoding I would like to have numOfItem be taken from the items.length.
I'm aware that I could set numOfItems with additional code when the items Vector is updated or with something like a "before encoding callback".
The question is if there is a more elegant solution. To me Header.numOfItems is redundant with Outer.items.length, so ideally only the
Encoder should know about numOfItems.

You could try building a Codec using consume() and start without building the Outer object:
case class OuterExpanded(
fieldBefore: Int, // Field before number of items in the binary encoding
fieldAdter: Int, // Field after number of items in the binary encoding
items: Vector[Item] // Encoded items
)
// Single Item codec
def itemC: Codec[Item] = (int32 :: int32).as[Item]
def outerExpandedC: Codec[OuterExpanded] = (
int32 :: // Field before count
int32.consume( c => // Item count
int32 :: // Field after count
vectorOfN(provide(c), itemC)) // 'consume' (use and forget) the count
(_.tail.head.length) // provide the length when encoding
).as[OuterExpanded]
As defined above, you get the following when encoding: outerExpandedC.encode(OuterExpanded(-1, -1, Vector(Item(1,2), Item(3,4)))) returns
Successful(BitVector(224 bits,
0xffffffff00000002fffffffe00000001000000020000000300000004))
^ ^ ^ ^-------^-> First Item
|-1 | |-2
|Vector length inserted between the two header fields
Afterwards, you can xmap() the Codec[OuterExpanded] to pack the other header fields together into their own object. Ie (adding two conversion methods to Outer and OuterExpanded):
def outerC: Codec[Outer] =
outerExpandedC.xmap(_.toOuter,_.expand)
case class OuterExpanded(fieldBefore: Int, fieldAfter: Int, items: Vector[Item]) {
def toOuter = Outer(Hdr(fieldBefore,fieldAfter), items)
}
case class Outer(header: Hdr, items: Vector[Item]) {
def expand = OuterExpanded(header.beforeField1, header.beforeField1, items)
}
This can probably be adapted to more complex cases, though I'm not entirely familar with shapeless' heterogeneous lists – or HList – and there might be nicer ways to get to the length of the vector rather than calling _.tail.head.length in the example above, especially if you end up with more than one field after the number of encoded values.
Also, the Codec scaladoc is a nice place to discover useful operators

Based on the previous answer I came up with something like the code below.
I used the consume trick form above and an AtomicInteger to hold the size of the vector.
import java.util.concurrent.atomic.AtomicInteger
import scala.Vector
import org.scalatest._
import scodec._
import scodec.Attempt._
import scodec.codecs._
import scodec.bits._
object SomeStructure {
case class Item(
address: Int,
size: Int)
def itemC: Codec[Item] = (int32 :: int32).as[Item]
case class Hdr(
beforeField1: Int,
// vectorSize would be here
afterField1: Int)
// vectorSize is an "in" param when encoding and an "out" param when decoding
def hdrC(vectorSize: AtomicInteger): Codec[Hdr] =
(int32 ::
int32.consume(c => {
vectorSize.set(c);
int32
})((i) => vectorSize.get)).as[Hdr]
case class Outer(
hdr: Hdr,
var items: Vector[Item])
def outerC() = {
// when decoding the length is in this atomic integer
// when encoding it is set before
val c = new AtomicInteger(-1)
(hdrC(c) :: lazily(vectorOfN(provide(c.get), itemC)))
.xmapc(identity)((g) => { c.set(g.tail.head.length); g })
}.as[Outer]
}
import SomeStructure._
class SomeStructureSpec extends FlatSpec with Matchers {
val bv = hex"ffffffff00000002ffffffff00000001000000020000000300000004".bits
val v = Vector(Item(1, 2), Item(3, 4))
val bv2 = hex"ffffffff00000003ffffffff000000010000000200000003000000040000000500000006".bits
val v2 = Vector(Item(1, 2), Item(3, 4), Item(5, 6))
val o = Outer(Hdr(-1, -1), v)
"outerC" should "encode" in {
o.items = v
outerC.encode(o) shouldBe Successful(bv)
o.items = v2
outerC.encode(o) shouldBe Successful(bv2)
}
it should "decode" in {
o.items = v
outerC.decode(bv) shouldBe Successful(DecodeResult(o, BitVector.empty))
o.items = v2
outerC.decode(bv2) shouldBe Successful(DecodeResult(o, BitVector.empty))
}
}

Related

F# type constraints indexable

I'm trying to make a type that should represent a "slice" of some indexable collection.
I know that there are some similar types in F# but not one that specifies the criteria that I need.
To do this it needs to carry a reference to the collection of type 'content and the content needs to be indexable. So I tried this constraint since a type only needs to have the member Item (get/set) so I tried this
type Slice<'a, 'content when 'content: (member Item: int -> 'a)>
This still throw the usual error
So is it possible to constrain a type to still be generic but constraint to be indexable?
I think something like this should work:
type Slice<'a, 'content when 'content: (member get_Item: int -> 'a)> =
{
Content : 'content
Start : int
Stop : int
}
with
member inline slice.get_Item(i) =
slice.Content.get_Item(slice.Start + i)
I've implemented get_Item on Slice as well, so you can take a slice of a slice. Here are some values of this type:
let strSlice =
{
Content = "hello"
Start = 1
Stop = 2
}
let arraySlice =
{
Content = [| 2; 4; 6; 8 |]
Start = 0
Stop = 3
}
let strSliceSlice =
{
Content = strSlice
Start = 0
Stop = 1
}
[<Interface>]
type Indexable<'a> =
abstract member Item: int -> 'a with get
[<Struct>]
type Slice<'a> =
{
content: Indexable<'a>
start: int
len: int
}
with
interface Indexable<'a> with
member I.Item with get(i) = I.[idx]
member S.Item with get(idx) =
if idx >= S.len
then raise(IndexOutOfRangeException())
else S.content.[S.start+idx]
This works.

can't get Kotlin to check if variable in listOf

I've tried this 10 different ways and i can't get this to work.
I want this Kotlin code to take in a string, check each character of that string against a listOf characters, and, if it is in that list, increase a counting variable by 1, so then at the end it can check if that counting variable is high enough to pass a test. this is taken straight from Sololearn: Code Coach - Password Validator. I have completed this code successfully already in Python (https://code.sololearn.com/c0fl17IMHPfC), but in trying to convert it over to Kotlin, it doesn't seem to work. The variables don't seem to register as true when compared to the elements in the listOf.
fun main() {
var password: String = readLine()!!
var numberCount: Int = 0
var numbers: List<String> = listOf("0","1","2","3","4","5","6","7","8","9")
var specialCount: Int = 0
var specialCharacters: List<String> = listOf("!","#","#","$","%","&","*")
if (password.length < 7) {
println("Weak")
} else {
for (character in password) {
println(character)
var numberCheck = numbers.contains(character)
println(numberCheck)
if (numberCheck == true) {
numberCount += 1
}
var specialCharactersCheck = specialCharacters.contains(character)
println(specialCharactersCheck)
if (specialCharactersCheck == true) {
specialCount += 1
}
}
println(numberCount)
println(specialCount)
if (numberCount < 2) {
println("Weak")
} else if (specialCount < 2) {
println("Weak")
} else {
println("Strong")
}
}
}
When I enter an input of "letssee43$#", the result of this code is:
l
false
false
e
false
false
t
false
false
s
false
false
s
false
false
e
false
false
e
false
false
4
false
false
3
false
false
$
false
false
false
false
0
0
Weak
Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.
Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly.
Your list is a list of Strings, but for (character in password) loops over the Chars in password. So you're trying to see if one of the Strings in your list is a specific Char, which it isn't, because they're two different types - a string with a single character in it is still a String, not a Char (that's why you're getting that type error)
There are lots of ways to do it (and there's nothing wrong with your code besides the Char/String thing!), personally I'd just do this:
var numbers = "0123456789"
var specialCharacters = "!##$%&*"
val password = "letssee43$#"
val nums = password.count { it in numbers }
val specials = password.count { it in specialCharacters }
println("nums: $nums, specials: $specials")
> nums: 2, specials: 2
count is iterating over the Chars in password and counting how many of them each character string contains. A String is treated like an array of Chars, so you can check it that way. (You could also add .toList() after the string declaration if you really want your characters stored in a list - that way it'll be a List<Char> so the lookup will still work.)
Or you could do things the way you are, and explicitly write out the listOf elements - but make them Chars instead, e.g. listOf('1') (single quotes) instead of listOf("1") (double quotes).
If you do want to search a list of strings for a match, you need to provide a String, so you need to convert your Char to one, e.g. by calling toString() on it, using a literal like "$character", etc.
edit like gidds points out below, sets are way more efficient for lookups like in or contains, so toSet() is a better idea than toList() unless you really need that ordered list for some reason. If you don't care about efficiency (like if you're not doing a lot of lookups) I'd personally just leave it as a string like in the code block up there - it's nice and simple. But if you do want to be more efficient, or if you do need a collection (like if you're matching against Strings) then a Set is ideal
I will give you another way to get the same result as you by using Extensions
fun main() {
var password: String = readln()
println("Password contain numbers amount: " + password.containNumbersAmount())
println("Password contain special characters amount: "+ password.containSpecialCharactersAmount())
println("Password Status : "+ password.validationResult())
}
fun String.containNumbersAmount() = count { it.isDigit() }
fun String.containSpecialCharactersAmount(): Int {
val specialCharacters = "!##$%&*"
return count { it in specialCharacters } }
fun String.validationResult() : String {
return when {
length < 7 -> "Weak"
containNumbersAmount() < 2 -> "Weak"
containSpecialCharactersAmount() < 2 -> "Weak"
else -> "Strong"
}
}
The problem is that your Lists contain Strings, so every time you call contains on them and pass a Char, it will always be false because a Char is not a String.
Probably, the best way to fix it is to declare Iterables of Chars to check them. Lists are Iterables, but so are ranges.
val password: String = readln()
var numberCount: Int = 0
val numbers: Iterable<Char> = '0'..'9'
var specialCount: Int = 0
val specialCharacters: List<Char> = listOf('!','#','#','$','%','&','*')
And just for your learning, there's a count function that takes a lambda argument that can make this kind of task much easier:
fun main() {
val password: String = readln()
val numbers = '0'..'9'
val specialCharacters = listOf('!','#','#','$','%','&','*')
val numberCount: Int = password.count { numbers.contains(it) }
val specialCount: Int = password.count { specialCharacters.contains(it) }
val result = when {
password.length < 7 || numberCount < 2 || specialCount < 2 -> "Weak"
else -> "Strong"
}
println(result)
}

Extract value out of Kotlin arrow Either type and assign it to const

It would be a basic question, but I couldn't figure out a solution. I need to initialize a constant out of the right-side value of below either type.
val test: Either<String, Int> = 1.right()
I tried something like below but it shrinks the scope of the constant.
when(test) {
is Either.Right -> {val get:Int = test.b}
is Either.Left -> println(test.a)
}
I want that get to be scoped outside of when statement. Is there any way to do it or Arrow Either is not made for this purpose?
The important question is: what should happen if the Either is Left. In this example it is created close to where it's used, so it is obvious to you as a developer. But to the compiler what is inside the Either can be either an Int or a String.
You can extract the value using for example fold:
val x = test.fold({ 0 }, {it}) // provide 0 as default in case the Either was a `Left`
// x = 1
another option is getOrElse
val test = 1.right()
val x = test.getOrElse { 42 } // again, default in case it was a `Left`
// x = 42
You can also work with it without unwrapping it:
val test = 1.right()
val testPlus10 = test.map { it + 10 } // adds 10 to `test` if it is `Right`, does nothing otherwise
val x = testPlus10.getOrElse { 0 } // unwrap by providing a default value
// x = 11
For more example check the official docs.
Recommended reading: How do I get the value out of my Monad

How to create variables in a for-loop with Kotlin

Given a maximum list size in parameter size and total amount of elements in parameter elements, I need to create a list of lists. What is the syntax for creating variables in for loops in Kotlin?
The way I'm thinking of going about this is to declare and create lists before elements are added to a list. Then, when a list has reached full capacity, it is switched out for the next list that is empty.
Here is the half-baked code:
fun listOfLists(size: Int, vararg elements: String): List<List<String>> {
var amountOfElements = elements.size
var currentSubList: List<String> = mutableListOf<String>()
val numberOfLists: Int = amountOfElements / size + 1
for (n in 0..numberOfLists) {
// Code for creating the total number of lists needed
}
for (e in elements) {
if (amountOfElements % size == 0) {
// Code for switching lists
}
amountOfElements--
}
As #dyukha correctly mentioned, what you need is chunked() function.
fun listOfLists(size: Int, vararg elements: String) =
elements.asList().chunked(size)
Or, if you want to be really efficient, you can also use asSequence():
fun listOfLists(size: Int, vararg elements: String) =
elements.asSequence().chunked(size)
chunked() doesn't work on Array, because it's defined on Iterable and Sequence, and Array doesn't implement any of them.

Using nested case classes with scodec

When defining my messages with scodec, I would like to use nested case classes. For example:
case class Foo(x: Int, y: Int)
object Foo {
def baseCodec = uint16 :: uint16
def codec = baseCodec.as[Foo]
}
case class Bar(a: Int, foo: Foo, b: Int)
object Bar {
val baseCodec = uint8 :: Foo.baseCodec :: uint16
val codec = baseCodec.as[Bar]
}
However, when trying to compile this I get the following:
error: Could not prove that shapeless.::[Int,shapeless.::[shapeless.::[Int,shapeless.::[Int,shapeless.HNil]],shapeless.::[Int,shapeless.HNil]]] can be converted to/from Bar.
val codec = baseCodec.as[Bar]
^
Is there a way of doing this? (In my real code, sometimes the nested case class appears at the beginning of the containing class' parameter list, sometimes in the middle and sometimes at the end).
I figured it out. You need to use the Codec, not the HList. This works:
object Bar {
//Foo.codec instead of Foo.baseCodec
val baseCodec = uint8 :: Foo.codec :: uint16
val codec = baseCodec.as[Bar]
}