cats.kernel.Semigroup Scala Examples

The following examples show how to use cats.kernel.Semigroup. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: package.scala    From sonar-scala   with GNU Lesser General Public License v3.0 6 votes vote down vote up
package com.mwz.sonar.scala

import scala.util.Try

import cats.instances.int.catsKernelStdGroupForInt
import cats.instances.map.catsKernelStdMonoidForMap
import cats.kernel.Semigroup
import cats.syntax.semigroup.catsSyntaxSemigroup

package object scoverage {

  
  private[scoverage] final implicit val FileCoverageSemigroup: Semigroup[FileCoverage] =
    new Semigroup[FileCoverage] {
      override def combine(a: FileCoverage, b: FileCoverage): FileCoverage = {
        val mergedFileScoverage = a.fileScoverage |+| b.fileScoverage
        val mergedLinesCoverage = a.linesCoverage |+| b.linesCoverage
        FileCoverage(mergedFileScoverage, mergedLinesCoverage)
      }
    }
} 
Example 2
Source File: CompressMapTest.scala    From spark-tools   with Apache License 2.0 5 votes vote down vote up
package io.univalence.parka

import cats.kernel.Semigroup
import org.scalatest.FunSuite

class CompressMapTest extends FunSuite {

  test("testApply") {

    val addInt = new Semigroup[Int] {
      override def combine(x: Int, y: Int): Int = x + y
    }

    assert(CompressMap(Map(Set(1, 2) -> 3, Set(2, 3) -> 2), 1)(addInt) == Map(Set(1, 2, 3) -> 5))

    assert(CompressMap(Map(Set(1, 2) -> 3, Set(2, 3) -> 2), 2)(addInt) == Map(Set(1, 2) -> 3, Set(2, 3) -> 2))

    assert(
      CompressMap(Map(
                    Set(1, 2)    -> 3,
                    Set(2, 3)    -> 2,
                    Set(1, 2, 3) -> 0,
                    Set(5, 6)    -> 7,
                    Set(6, 7)    -> 1,
                    Set(5, 6, 7) -> 0
                  ),
                  2)(addInt) == Map(Set(1, 2, 3) -> 5, Set(5, 6, 7) -> 8)
    )

  }

} 
Example 3
Source File: MapImplicits.scala    From matcher   with MIT License 5 votes vote down vote up
package com.wavesplatform.dex.fp

import cats.Group
import cats.instances.map.catsKernelStdMonoidForMap
import cats.kernel.Semigroup

object MapImplicits {

  implicit def group[K, V](implicit vGroup: Group[V]): Group[Map[K, V]] = new Group[Map[K, V]] {
    override def inverse(a: Map[K, V]): Map[K, V]               = a.map { case (k, v) => k -> vGroup.inverse(v) }
    override def empty: Map[K, V]                               = Map.empty
    override def combine(x: Map[K, V], y: Map[K, V]): Map[K, V] = catsKernelStdMonoidForMap[K, V].combine(x, y)
  }

  
  implicit def cleaningGroup[K, V](implicit vGroup: Group[V]): Group[Map[K, V]] = new Group[Map[K, V]] {

    override def inverse(a: Map[K, V]): Map[K, V] = a.map { case (k, v) => k -> vGroup.inverse(v) }
    override def empty: Map[K, V]                 = Map.empty

    override def combine(xs: Map[K, V], ys: Map[K, V]): Map[K, V] = {
      val (lessXs, biggerXs) = if (xs.size <= ys.size) (xs, ys) else (ys, xs)
      nonEmpty(lessXs).foldLeft(nonEmpty(biggerXs)) {
        case (r, (k, v)) =>
          val updatedV = Semigroup.maybeCombine(v, r.get(k))
          if (updatedV == vGroup.empty) r - k
          else r.updated(k, updatedV)
      }
    }

    private def nonEmpty(xs: Map[K, V]): Map[K, V] = xs.filterNot { case (_, v) => v == 0 }
  }
} 
Example 4
Source File: Plugin.scala    From sbt-kubeyml   with MIT License 5 votes vote down vote up
package kubeyml.ingress.plugin

import java.io.File

import cats.kernel.Semigroup
import kubeyml.ingress._
import kubeyml.service.Service
import cats.syntax.semigroup._
import kubeyml.deployment.plugin.Keys.kube
import json_support._
import kubeyml.plugin._
import kubeyml.service.plugin.KubeServicePlugin
import sbt.AutoPlugin
import sbt.util.Logger

object KubeIngressPlugin extends AutoPlugin {
  override def trigger = noTrigger
  override def requires = KubeServicePlugin

  override val projectSettings = sbt.inConfig(kube)(Keys.ingressSettings)

}

object Plugin {

  implicit val serviceValidationSemigroup: Semigroup[Either[List[IngressFailure], Ingress]] =
    (x: Either[List[IngressFailure], Ingress], y: Either[List[IngressFailure], Ingress]) =>
      (x, y) match {
        case (Left(failures), Left(moreFailures)) => Left(failures ++ moreFailures)
        case (Right(_), l @ Left(_))              => l
        case (l @ Left(_), Right(_))              => l
        case (Right(_), r @ Right(_))             => r
      }

  sealed trait IngressFailure {
    def message: String
  }

  case class PortMappingFailure private[plugin] (port: Int) extends IngressFailure {
    override def message: String = s"Port $port declared in ingress was not found in the service definition"
  }

  case class ServiceNameFailure private[plugin] (serviceName: String, ingressService: String) extends IngressFailure {

    override def message: String =
      s"Service name '$ingressService' in ingress does not match name in service definition $serviceName"
  }

  private[plugin] def validatePortMappings(service: Service, ingress: Ingress): Either[List[IngressFailure], Ingress] = {
    ingress match {
      case CustomIngress(_, _, _, Spec(rules), _) =>
        val validatedResult = rules
          .flatMap {
            case HttpRule(_, paths) =>
              paths.map {
                case Path(ServiceMapping(name, port), _) =>
                  val portMatching =
                    service.spec.ports
                      .find(_.port == port)
                      .map(_ => ingress)
                      .toRight[List[IngressFailure]](List(PortMappingFailure(port.value)))

                  val nameMatching = Either.cond(
                    name == service.name,
                    ingress,
                    List(ServiceNameFailure(service.name.value, name.value))
                  )
                  portMatching |+| nameMatching
              }
          }
          .fold(Right(ingress))(_ |+| _)
        validatedResult
    }
  }

  def generate(service: Service, ingress: Ingress, buildTarget: File, log: Logger) = {
    validatePortMappings(service, ingress)
      .map { ingress =>
        generateIngress(ingress, buildTarget)
      }
      .left
      .map(_.foreach(f => log.error(f.message)))
      .merge
  }

  private[plugin] def generateIngress(ingress: Ingress, buildTarget: File): Unit =
    writePlan(ingress, buildTarget, "ingress")

} 
Example 5
Source File: ValidationExtension.scala    From franklin   with Apache License 2.0 5 votes vote down vote up
package com.azavea.franklin.extensions.validation

import cats.data.NonEmptyList
import cats.data.Validated.{Invalid, Valid}
import cats.kernel.Semigroup
import com.azavea.stac4s.extensions.ItemAssetExtension
import com.azavea.stac4s.extensions.{ExtensionResult, ItemExtension, LinkExtension}
import eu.timepit.refined.types.string.NonEmptyString
import io.circe._
import io.circe.refined._
import io.circe.syntax._

final case class ValidationExtension(
    attemptedExtensions: NonEmptyList[NonEmptyString],
    errors: List[NonEmptyString]
)

object ValidationExtension {

  implicit val decValidationExtension: Decoder[ValidationExtension] = Decoder.forProduct2(
    "validation:attemptedExtensions",
    "validation:errors"
  )((extensions: NonEmptyList[NonEmptyString], errors: List[NonEmptyString]) =>
    ValidationExtension(extensions, errors)
  )

  implicit val encValidationExtension: Encoder.AsObject[ValidationExtension] = Encoder
    .AsObject[Map[String, Json]]
    .contramapObject((validationExtensionFields: ValidationExtension) =>
      Map(
        "validation:attemptedExtensions" -> validationExtensionFields.attemptedExtensions.asJson,
        "validation:errors"              -> validationExtensionFields.errors.asJson
      )
    )

  implicit val validationExtensionItemExtension: ItemExtension[ValidationExtension] =
    ItemExtension.instance

  implicit val validationExtensionLinkExtension: LinkExtension[ValidationExtension] =
    LinkExtension.instance

  implicit val validationExtensionAssetExtension: ItemAssetExtension[ValidationExtension] =
    ItemAssetExtension.instance

  implicit val semigroupValidationExtension: Semigroup[ValidationExtension] =
    new Semigroup[ValidationExtension] {

      def combine(x: ValidationExtension, y: ValidationExtension): ValidationExtension = {
        ValidationExtension(
          x.attemptedExtensions.concat(y.attemptedExtensions.toList),
          x.errors ++ y.errors
        )
      }
    }

  def success(name: NonEmptyString) = ValidationExtension(
    NonEmptyList.of(name),
    Nil
  )

  def failure(name: NonEmptyString, errors: List[DecodingFailure]) =
    ValidationExtension(NonEmptyList.of(name), errors map { (err: DecodingFailure) =>
      NonEmptyString.from(CursorOp.opsToPath(err.history))
    } collect {
      case Right(v) => v
    })

  def fromResult[T](result: ExtensionResult[T], name: NonEmptyString) = result match {
    case Invalid(errs) =>
      failure(name, errs collect {
        case e: DecodingFailure => e
      })
    case Valid(_) =>
      success(name)
  }
} 
Example 6
Source File: TypeRecorder.scala    From morpheus   with Apache License 2.0 5 votes vote down vote up
package org.opencypher.okapi.ir.impl.typer

import cats.kernel.Semigroup
import org.opencypher.okapi.api.types.CypherType
import org.opencypher.v9_0.expressions.Expression
import org.opencypher.v9_0.util.Ref

import scala.annotation.tailrec

final case class TypeRecorder(recordedTypes: List[(Ref[Expression], CypherType)]) {

  def toMap: Map[Ref[Expression], CypherType] = toMap(Map.empty, recordedTypes)

  @tailrec
  private def toMap(
      m: Map[Ref[Expression], CypherType],
      recorded: Seq[(Ref[Expression], CypherType)]): Map[Ref[Expression], CypherType] =
    recorded.headOption match {
      case Some((ref, t)) =>
        m.get(ref) match {
          case Some(t2) => toMap(m.updated(ref, t.join(t2)), recorded.tail)
          case None     => toMap(m.updated(ref, t), recorded.tail)
        }
      case None =>
        m
    }
}

object TypeRecorder {

  def from(tuples: List[(Expression, CypherType)]): TypeRecorder = {
    TypeRecorder(tuples.map {
      case (e, t) => Ref(e) -> t
    })
  }

  def single(entry: (Expression, CypherType)): TypeRecorder = {
    val (expr, cypherType) = entry
    TypeRecorder(List(Ref(expr) -> cypherType))
  }

  implicit object recorderSemigroup extends Semigroup[TypeRecorder] {
    override def combine(x: TypeRecorder, y: TypeRecorder): TypeRecorder = {
      TypeRecorder(x.recordedTypes ++ y.recordedTypes)
    }
  }

} 
Example 7
Source File: Constant.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.optics.data

import cats.kernel.{Monoid, Semigroup}
import cats.syntax.monoid._
import cats.{Applicative, Apply, Bifunctor, Functor}

sealed trait Constant[+A, +B] {
  def value: A
  def retag[C]: Constant[A, C]
}

object Constant extends ConstantLowPrior {
  def apply[A](a: A) = Impl(a)

  def of[B] = new Apply[B]

  class Apply[B] {
    def apply[A](a: A): Constant[A, B] = Impl(a)
  }

  final case class Impl[+A](value: A) extends Constant[A, Nothing] {
    def retag[C]: Constant[A, C] = this
  }

  implicit val bifunctor: Bifunctor[Constant] = new Bifunctor[Constant] {
    def bimap[A, B, C, D](fab: Constant[A, B])(f: A => C, g: B => D): Constant[C, D] = Impl(f(fab.value))
  }

  implicit def applicative[X: Monoid]: Applicative[Constant[X, *]] = new Applicative[Constant[X, *]] {
    def pure[A](x: A): Constant[X, A]                                         = Impl(Monoid.empty[X])
    def ap[A, B](ff: Constant[X, A => B])(fa: Constant[X, A]): Constant[X, B] = Impl(ff.value |+| fa.value)
  }
}

class ConstantLowPrior extends ConstantLowPrior2 {
  implicit def applyInstance[X: Semigroup]: Apply[Constant[X, *]] = new Apply[Constant[X, *]] {
    def ap[A, B](ff: Constant[X, A => B])(fa: Constant[X, A]): Constant[X, B] = Constant(ff.value |+| fa.value)
    def map[A, B](fa: Constant[X, A])(f: A => B): Constant[X, B]              = fa.retag
  }

}

class ConstantLowPrior2 {
  implicit def functor[X]: Functor[Constant[X, *]] = Constant.bifunctor.rightFunctor
} 
Example 8
Source File: Applied.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.optics
import cats.data.NonEmptyList
import cats.kernel.Semigroup
import cats.{Applicative, Apply, Monoid}
import tofu.optics.classes.Category2
import tofu.optics.tags.{PTagApply, Tagger}

final case class Applied[O[_, _, _, _], S, T, A, B](s: S, o: O[S, T, A, B]) {
  def >>[O1[s, t, a, b] >: O[s, t, a, b]: Category2, U, V](o1: O1[A, B, U, V]): Applied[O1, S, T, U, V] =
    Applied(s, Category2.compose(o1, o))

  def >[O1[s, t, a, b] >: O[s, t, a, b]](tagger: Tagger[O1]): AppliedWithTag[O1, S, T, A, B, tagger.Tag] =
    AppliedWithTag(s, o)

  def put(b: B)(implicit ev: O[S, T, A, B] <:< PUpdate[S, T, A, B]): T = ev(o).put(s, b)

  def update(f: A => B)(implicit ev: O[S, T, A, B] <:< PUpdate[S, T, A, B]): T = ev(o).update(s, f)

  def get(implicit ev: O[S, T, A, B] <:< PExtract[S, T, A, B]): A = ev(o).extract(s)

  def downcast(implicit ev: O[S, T, A, B] <:< PDowncast[S, T, A, B]): Option[A] = ev(o).downcast(s)

  def traverse[G[+_]: Applicative](f: A => G[B])(implicit ev: O[S, T, A, B] <:< PItems[S, T, A, B]): G[T] =
    ev(o).traverse(s)(f)

  def foldMap[M: Monoid](f: A => M)(implicit ev: O[S, T, A, B] <:< PFolded[S, T, A, B]): M =
    ev(o).foldMap(s)(f)

  def reduceMap[M: Semigroup](f: A => M)(implicit ev: O[S, T, A, B] <:< PReduced[S, T, A, B]): M =
    ev(o).reduceMap(s)(f)

  def getAll1(implicit ev: O[S, T, A, B] <:< PReduced[S, T, A, B]): NonEmptyList[A] =
    ev(o).getAll1(s)

  def getAll(implicit ev: O[S, T, A, B] <:< PFolded[S, T, A, B]): List[A] =
    ev(o).getAll(s)

  def traverse1[G[+_]: Apply](f: A => G[B])(implicit ev: O[S, T, A, B] <:< PRepeated[S, T, A, B]): G[T] =
    ev(o).traverse1(s)(f)
}

final case class AppliedWithTag[O[_, _, _, _], S, T, A, B, Tag](s: S, o: O[S, T, A, B]) {
  def >@[X, U, V](x: X)(implicit tag: PTagApply[O, A, B, U, V, Tag, X], cat: Category2[O]): Applied[O, S, T, U, V] =
    Applied(s, cat.compose(tag.continue(x), o))

  def >[O1[s, t, a, b] >: O[s, t, a, b], U, V](
      tagger: Tagger[O1]
  )(implicit tag: PTagApply[O, A, B, U, V, Tag, Unit], cat: Category2[O]): AppliedWithTag[O1, S, T, U, V, tagger.Tag] =
    end > tagger

  def >>[O1[s, t, a, b] >: O[s, t, a, b]: Category2, U, V, X, Y](o1: O1[U, V, X, Y])(implicit
      tag: PTagApply[O, A, B, U, V, Tag, Unit],
      cat: Category2[O]
  ): Applied[O1, S, T, X, Y] =
    end >> o1

  def end[U, V](implicit tag: PTagApply[O, A, B, U, V, Tag, Unit], cat: Category2[O]): Applied[O, S, T, U, V] =
    >@ {}
}

object chain {
  def to[T]          = new ChainTo[T]
  def apply[S](s: S) = Applied(s, PSame.id[S, S])

  class ChainTo[T] {
    def apply[S](s: S) = Applied(s, PSame.id[S, T])
  }
} 
Example 9
Source File: Merge.scala    From tofu   with Apache License 2.0 5 votes vote down vote up
package tofu.data
package derived

import java.time.{Instant, LocalDate, LocalDateTime, ZonedDateTime}

import cats.kernel.Semigroup
import magnolia.{CaseClass, Magnolia, SealedTrait}
import simulacrum.typeclass
import derevo.Derivation

@typeclass trait Merge[A] {
  def merge(a: A, b: A): A
}

trait MergeInstances1 {
  type Typeclass[A] = Merge[A]

  def combine[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] =
    (a, b) => caseClass.construct(p => p.typeclass.merge(p.dereference(a), p.dereference(b)))

  def dispatch[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] =
    (a, b) => sealedTrait.dispatch(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a }

  implicit def instance[A]: Merge[A] = macro Magnolia.gen[A]
}

object Merge extends Derivation[Merge] with MergeInstances1 {
  implicit def optionInstance[A](implicit m: Merge[A]): Merge[Option[A]] =
    (ao, bo) => ao.fold(bo)(a => bo.fold(ao)(b => Some(m.merge(a, b))))

  implicit def primitiveInstance[A: Primitive]: Merge[A] = (a: A, _: A) => a

  sealed class Primitive[A]
  final implicit object primitiveByte          extends Primitive[Byte]
  final implicit object primitiveShort         extends Primitive[Short]
  final implicit object primitiveInt           extends Primitive[Int]
  final implicit object primitiveLong          extends Primitive[Long]
  final implicit object primitiveChar          extends Primitive[Char]
  final implicit object primitiveFloat         extends Primitive[Float]
  final implicit object primitiveDouble        extends Primitive[Double]
  final implicit object primitiveUnit          extends Primitive[Unit]
  final implicit object primitiveBigDecimal    extends Primitive[BigDecimal]
  final implicit object primitiveBigInt        extends Primitive[BigInt]
  final implicit object primitiveLocalDateTime extends Primitive[LocalDateTime]
  final implicit object primitiveZonedDateTime extends Primitive[ZonedDateTime]
  final implicit object primitiveLocalDate     extends Primitive[LocalDate]
  final implicit object primitiveInstant       extends Primitive[Instant]
  final implicit object primitiveString        extends Primitive[String]
}

object Merged {
  trait OpaqueTag extends Any
  type Base = Any { type MergedOpaque }

  type Mer[A] <: Base with OpaqueTag

  def apply[A](value: A): Mer[A] = value.asInstanceOf[Mer[A]]

  implicit final class MergedOps[A](private val mer: Mer[A]) extends AnyVal {
    def value: A = mer.asInstanceOf[A]
  }

  implicit def mergedSemigroup[A: Merge]: Semigroup[Merged[A]] =
    (x, y) => apply(Merge[A].merge(x.value, y.value))
} 
Example 10
Source File: CatsEffectMtlInstances.scala    From meow-mtl   with MIT License 5 votes vote down vote up
package com.olegpy.meow.internal

import cats.effect.concurrent.Ref
import cats.kernel.Semigroup
import cats.mtl._
import cats.syntax.functor._
import cats.syntax.semigroup._
import cats.{Applicative, Functor, Monad}

private[meow] object CatsEffectMtlInstances {
  class RefMonadState[F[_]: Monad, S](ref: Ref[F, S]) extends MonadState[F, S] {
    val monad: Monad[F] = implicitly
    def get: F[S] = ref.get
    def set(s: S): F[Unit] = ref.set(s)
    def inspect[A](f: S => A): F[A] = ref.get.map(f)
    def modify(f: S => S): F[Unit] = ref.update(f)
  }

  class RefFunctorTell[F[_]: Functor, L: Semigroup](ref: Ref[F, L])
    extends FunctorTell[F, L] with DefaultFunctorTell[F, L] {
    val functor: Functor[F] = implicitly
    def tell(l: L): F[Unit] = ref.update(_ |+| l)
  }

  class RefApplicativeAsk[F[_]: Applicative, S](ref: Ref[F, S])
    extends ApplicativeAsk[F, S] with DefaultApplicativeAsk[F, S] {
    val applicative: Applicative[F] = implicitly
    def ask: F[S] = ref.get
  }
} 
Example 11
Source File: TracedResult.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.transaction.smart.script.trace

import cats.implicits._
import cats.{Applicative, Apply, Functor}
import cats.kernel.Semigroup
import com.wavesplatform.api.http.ApiError
import com.wavesplatform.transaction.Transaction
import play.api.libs.json.{JsObject, Json}

final case class TracedResult[+E, +A](
    resultE: Either[E, A],
    trace: List[TraceStep] = Nil
) {
  def transformE[B, E1](f: Either[E, A] => TracedResult[E1, B]): TracedResult[E1, B] = {
    val newResultE = f(resultE)
    newResultE.copy(trace = this.trace ::: newResultE.trace)
  }

  def flatMap[B, E1 >: E](f: A => TracedResult[E1, B]): TracedResult[E1, B] = {
    resultE match {
      case Left(_) => this.asInstanceOf[TracedResult[E1, B]]
      case Right(value) =>
        val newResult = f(value)
        newResult.copy(trace = this.trace ::: newResult.trace)
    }
  }

  def map[B](f: A => B): TracedResult[E, B] = copy(resultE.map(f))

  def leftMap[E1](f: E => E1): TracedResult[E1, A] = copy(resultE.leftMap(f))

  def json(implicit ev1: E => ApiError, ev2: A => Transaction): JsObject = {
    val resultJson = resultE match {
      case Right(value) => value.json()
      case Left(e)      => e.json
    }
    resultJson ++ Json.obj("trace" -> trace.map(_.json))
  }

  def loggedJson(implicit ev1: E => ApiError, ev2: A => Transaction): JsObject = {
    val resultJson = resultE match {
      case Right(value) => value.json()
      case Left(e)      => e.json
    }
    resultJson ++ Json.obj("trace" -> trace.map(_.loggedJson))
  }
}

object TracedResult {
  implicit def wrapE[A, E](e: Either[E, A]): TracedResult[E, A] = TracedResult(e)

  implicit def wrapValue[A, E](value: A): TracedResult[E, A] = TracedResult(Right(value))

  implicit def tracedResultSemigroup[A: Semigroup, E]: Semigroup[TracedResult[E, A]] =
    (a, b) =>
      TracedResult(
        a.resultE |+| b.resultE,
        if (a.resultE.isRight) a.trace |+| b.trace else a.trace
      )

  implicit def applicativeTracedResult[L]: Applicative[TracedResult[L, ?]] with Apply[TracedResult[L, ?]] with Functor[TracedResult[L, ?]]  = new Applicative[TracedResult[L, ?]] {
    def pure[A](v:A) = wrapValue[A, L](v)
    def ap[A,B](fb: TracedResult[L, A=>B])(fa: TracedResult[L, A]) : TracedResult[L, B] = {
      TracedResult(fa.resultE ap fb.resultE, fa.trace ++ fb.trace)
    }
    override def product[A,B](fa: TracedResult[L, A], fb: TracedResult[L, B]) : TracedResult[L, (A,B)] = {
      TracedResult(fa.resultE product fb.resultE, fa.trace ++ fb.trace)
    }
    override def map[A,B](x: TracedResult[L, A])(f: A=>B) : TracedResult[L, B] = {
      TracedResult[L,B](x.resultE map f, x.trace)
    }
  }
} 
Example 12
Source File: NewtypeBench.scala    From newts   with Apache License 2.0 5 votes vote down vote up
package newts.bench

import java.util.concurrent.TimeUnit

import cats.Cartesian
import cats.instances.list._
import cats.instances.string._
import cats.kernel.{Monoid, Semigroup}
import cats.syntax.foldable._
import newts.bench.scalaz.{ConjunctionZ, ZipListZ, conjunctionZMonoid, zipListZApply}
import newts.bench.shapeless.{ConjunctionS, conjunctionSMonoid}
import newts.{All, Min, ZipList}
import org.openjdk.jmh.annotations._

@Warmup(     iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 3, jvmArgsAppend = Array("-XX:+UseG1GC", "-Xms1G", "-Xmx1G"))
@BenchmarkMode(Array(Mode.Throughput))
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
class NewtypeBench {

  def and(b1: Boolean, b2: Boolean): Boolean = b1 && b2

  @Benchmark def stdAllCombine1      : Boolean      = and(true, false)
  @Benchmark def anyvalAllCombine1   : All          = Monoid[All].combine(All(true) , All(false))
  @Benchmark def scalazAllCombine1   : ConjunctionZ = Monoid[ConjunctionZ].combine(scalaz.True, scalaz.False)
  @Benchmark def shapelessAllCombine1: ConjunctionS = Monoid[ConjunctionS].combine(shapeless.True, shapeless.False)

  val booleans: List[Boolean]      = List.fill(99)(true) :+ false
  val alls    : List[All]          = booleans.map(All(_))
  val allZ    : List[ConjunctionZ] = booleans.map(scalaz.fromBoolean)
  val allS    : List[ConjunctionS] = booleans.map(shapeless.fromBoolean)

  @Benchmark def stdAllCombineAll      : Boolean      = booleans.foldLeft(true)(_ && _)
  @Benchmark def anyvalAllCombineAll   : All          = alls.combineAll
  @Benchmark def scalazAllCombineAll   : ConjunctionZ = allZ.combineAll
  @Benchmark def shapelessAllCombineAll: ConjunctionS = allS.combineAll

//  val intList    : List[Int]      = 1.to(100).toList
//  val intZipList : ZipList[Int]   = ZipList(intList)
//  val intZipListz: ZipListZ[Int]  = scalaz.tag(intList)
//
//  @Benchmark def stdIntProduct   : List[(Int, Int)]     = intList.zip(intList)
//  @Benchmark def anyvalIntProduct: ZipList[(Int, Int)]  = Cartesian[ZipList].product(intZipList, intZipList)
//  @Benchmark def scalazIntProduct: ZipListZ[(Int, Int)] = Cartesian[ZipListZ].product(intZipListz, intZipListz)

  @Benchmark def stdIntMin   : String      = Ordering[String].min("abcdefgh", "abcdefghz")
  @Benchmark def anyvalIntMin: Min[String] = Semigroup[Min[String]].combine(Min("abcdefgh"), Min("abcdefghz"))

}