diff --git a/JavaDecompiler.md b/JavaDecompiler.md new file mode 100644 index 0000000..bd88fcf --- /dev/null +++ b/JavaDecompiler.md @@ -0,0 +1,163 @@ +```java +// class version 52.0 (52) +// access flags 0x21 +public class ScalaTrial { + + // compiled from: ScalaTrial.scala + + @Lscala/reflect/ScalaSignature;(bytes="\u0006\u0005\r2A!\u0002\u0004\u0001\u0013!)\u0001\u0003\u0001C\u0001#!)A\u0003\u0001C\u0001+!)Q\u0004\u0001C\u0001=!)\u0011\u0005\u0001C\u0001E\u0009Q1kY1mCR\u0013\u0018.\u00197\u000b\u0003\u001d\u0009q\u0001P3naRLhh\u0001\u0001\u0014\u0005\u0001Q\u0001CA\u0006\u000f\u001b\u0005a!\"A\u0007\u0002\u000bM\u001c\u0017\r\\1\n\u0005=a!AB!osJ+g-\u0001\u0004=S:LGO\u0010\u000b\u0002%A\u00111\u0003A\u0007\u0002\r\u0005)Q.\u001e7uSR\u0019a#G\u000e\u0011\u0005-9\u0012B\u0001\r\r\u0005\rIe\u000e\u001e\u0005\u00065\u0009\u0001\rAF\u0001\u0002q\")AD\u0001a\u0001-\u0005\u0009\u00110\u0001\u0003qYV\u001cHc\u0001\u000c A!)!d\u0001a\u0001-!)Ad\u0001a\u0001-\u0005!\u0001/\u001b9f)\u00051\u0002") + + ATTRIBUTE ScalaSig : unknown + + ATTRIBUTE ScalaInlineInfo : unknown + // access flags 0x19 + public final static INNERCLASS java/lang/invoke/MethodHandles$Lookup java/lang/invoke/MethodHandles Lookup + // access flags 0x9 + public static INNERCLASS scala/util/package$chaining$ scala/util/package chaining$ + + // access flags 0x1 + public multi(II)I + // parameter final x + // parameter final y + L0 + LINENUMBER 4 L0 + ILOAD 1 + ILOAD 2 + IMUL + IRETURN + L1 + LOCALVARIABLE this LScalaTrial; L0 L1 0 + LOCALVARIABLE x I L0 L1 1 + LOCALVARIABLE y I L0 L1 2 + MAXSTACK = 2 + MAXLOCALS = 3 + + // access flags 0x1 + public plus(II)I + // parameter final x + // parameter final y + L0 + LINENUMBER 5 L0 + ILOAD 1 + ILOAD 2 + IADD + IRETURN + L1 + LOCALVARIABLE this LScalaTrial; L0 L1 0 + LOCALVARIABLE x I L0 L1 1 + LOCALVARIABLE y I L0 L1 2 + MAXSTACK = 2 + MAXLOCALS = 3 + + // access flags 0x1 + public pipe()I + L0 + LINENUMBER 8 L0 + GETSTATIC scala/util/ChainingOps$.MODULE$ : Lscala/util/ChainingOps$; + GETSTATIC scala/util/package$chaining$.MODULE$ : Lscala/util/package$chaining$; + GETSTATIC scala/util/ChainingOps$.MODULE$ : Lscala/util/ChainingOps$; + GETSTATIC scala/util/package$chaining$.MODULE$ : Lscala/util/package$chaining$; + ICONST_2 + INVOKESTATIC scala/runtime/BoxesRunTime.boxToInteger (I)Ljava/lang/Integer; + INVOKEVIRTUAL scala/util/package$chaining$.scalaUtilChainingOps (Ljava/lang/Object;)Ljava/lang/Object; + ALOAD 0 + INVOKEDYNAMIC apply$mcII$sp(LScalaTrial;)Lscala/runtime/java8/JFunction1$mcII$sp; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + (I)I, + // handle kind 0x6 : INVOKESTATIC + ScalaTrial.$anonfun$pipe$1(LScalaTrial;I)I, + (I)I, + 1 + ] + INVOKEVIRTUAL scala/util/ChainingOps$.pipe$extension (Ljava/lang/Object;Lscala/Function1;)Ljava/lang/Object; + INVOKEVIRTUAL scala/util/package$chaining$.scalaUtilChainingOps (Ljava/lang/Object;)Ljava/lang/Object; + ALOAD 0 + INVOKEDYNAMIC apply$mcII$sp(LScalaTrial;)Lscala/runtime/java8/JFunction1$mcII$sp; [ + // handle kind 0x6 : INVOKESTATIC + java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; + // arguments: + (I)I, + // handle kind 0x6 : INVOKESTATIC + ScalaTrial.$anonfun$pipe$2(LScalaTrial;I)I, + (I)I, + 1 + ] + INVOKEVIRTUAL scala/util/ChainingOps$.pipe$extension (Ljava/lang/Object;Lscala/Function1;)Ljava/lang/Object; + INVOKESTATIC scala/runtime/BoxesRunTime.unboxToInt (Ljava/lang/Object;)I + ISTORE 1 + L1 + LINENUMBER 9 L1 + ILOAD 1 + L2 + IRETURN + L3 + LOCALVARIABLE x I L1 L2 1 + LOCALVARIABLE this LScalaTrial; L0 L3 0 + MAXSTACK = 5 + MAXLOCALS = 2 + + // access flags 0x1019 + public final static synthetic $anonfun$pipe$1(LScalaTrial;I)I + // parameter final synthetic $this + // parameter final x$1 + L0 + LINENUMBER 8 L0 + ALOAD 0 + ILOAD 1 + ICONST_3 + INVOKEVIRTUAL ScalaTrial.plus (II)I + IRETURN + L1 + LOCALVARIABLE $this LScalaTrial; L0 L1 0 + LOCALVARIABLE x$1 I L0 L1 1 + MAXSTACK = 3 + MAXLOCALS = 2 + + // access flags 0x1019 + public final static synthetic $anonfun$pipe$2(LScalaTrial;I)I + // parameter final synthetic $this + // parameter final x$2 + L0 + LINENUMBER 8 L0 + ALOAD 0 + ILOAD 1 + ICONST_2 + INVOKEVIRTUAL ScalaTrial.multi (II)I + IRETURN + L1 + LOCALVARIABLE $this LScalaTrial; L0 L1 0 + LOCALVARIABLE x$2 I L0 L1 1 + MAXSTACK = 3 + MAXLOCALS = 2 + + // access flags 0x1 + public ()V + L0 + LINENUMBER 3 L0 + ALOAD 0 + INVOKESPECIAL java/lang/Object. ()V + RETURN + L1 + LOCALVARIABLE this LScalaTrial; L0 L1 0 + MAXSTACK = 1 + MAXLOCALS = 1 + + // access flags 0x100A + private static synthetic $deserializeLambda$(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object; + ALOAD 0 + INVOKEDYNAMIC lambdaDeserialize(Ljava/lang/invoke/SerializedLambda;)Ljava/lang/Object; [ + // handle kind 0x6 : INVOKESTATIC + scala/runtime/LambdaDeserialize.bootstrap(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; + // arguments: + // handle kind 0x6 : INVOKESTATIC + ScalaTrial.$anonfun$pipe$1(LScalaTrial;I)I, + // handle kind 0x6 : INVOKESTATIC + ScalaTrial.$anonfun$pipe$2(LScalaTrial;I)I + ] + ARETURN + MAXSTACK = 1 + MAXLOCALS = 1 +} +``` diff --git a/SharpDecompiler.md b/SharpDecompiler.md new file mode 100644 index 0000000..5250352 --- /dev/null +++ b/SharpDecompiler.md @@ -0,0 +1,327 @@ +```cs +// Decompiled with JetBrains decompiler +// Type: Program +// Assembly: FSharpTrial, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null +// MVID: D85670CC-88CF-0636-AC1A-2F1C7D3E921B +// Assembly location: C:\Users\volok\RiderProjects\Solution1\CSharpTesting\bin\Debug\net6.0\FSharpTrial.dll + +using Microsoft.FSharp.Core; +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[CompilationMapping(SourceConstructFlags.Module)] +public static class Program +{ + [CompilationArgumentCounts(new int[] {1, 1})] + public static int multi(int x, int y) => x * y; + + [CompilationArgumentCounts(new int[] {1, 1})] + public static int plus(int x, int y) => x + y; + + [CompilationArgumentCounts(new int[] {1, 1, 1})] + public static int result(int x, int y, int z) + { + int y1 = Program.multi(x, y); + return Program.plus(z, y1); + } + + public static void unionTrial(int x) + { + Program.IntOrBool intOrBool1 = Program.IntOrBool.NewI(x); + Program.IntOrBool intOrBool2 = Program.IntOrBool.NewB(x % 2 == 0); + ExtraTopLevelOperators.PrintFormatLine((PrintfFormat) new PrintfFormat("%d%P()", new object[1] + { + (object) x + }, (Type[]) null)); + ExtraTopLevelOperators.PrintFormatLine((PrintfFormat) new PrintfFormat("%P() is odd?", new object[1] + { + (object) intOrBool1 + }, (Type[]) null)); + ExtraTopLevelOperators.PrintFormatLine((PrintfFormat) new PrintfFormat("%P()!", new object[1] + { + (object) intOrBool2 + }, (Type[]) null)); + } + + [DebuggerDisplay("{__DebugDisplay(),nq}")] + [CompilationMapping(SourceConstructFlags.SumType)] + [Serializable] + [StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)] + public abstract class IntOrBool : + IEquatable, + IStructuralEquatable, + IComparable, + IComparable, + IStructuralComparable + { + [CompilerGenerated] + [DebuggerNonUserCode] + internal IntOrBool() + { + } + + [CompilationMapping(SourceConstructFlags.UnionCase, 0)] + public static Program.IntOrBool NewI(int item) => (Program.IntOrBool) new Program.IntOrBool.I(item); + + [CompilerGenerated] + [DebuggerNonUserCode] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public bool IsI + { + [DebuggerNonUserCode] get => this is Program.IntOrBool.I; + } + + [DebuggerNonUserCode] + public bool get_IsI() => this is Program.IntOrBool.I; + + [CompilationMapping(SourceConstructFlags.UnionCase, 1)] + public static Program.IntOrBool NewB(bool item) => (Program.IntOrBool) new Program.IntOrBool.B(item); + + [CompilerGenerated] + [DebuggerNonUserCode] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public bool IsB + { + [DebuggerNonUserCode] get => this is Program.IntOrBool.B; + } + + [DebuggerNonUserCode] + public bool get_IsB() => this is Program.IntOrBool.B; + + [CompilerGenerated] + [DebuggerNonUserCode] + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + public int Tag + { + [DebuggerNonUserCode] get => this is Program.IntOrBool.B ? 1 : 0; + } + + [DebuggerNonUserCode] + public int get_Tag() => this is Program.IntOrBool.B ? 1 : 0; + + [CompilerGenerated] + [DebuggerNonUserCode] + [SpecialName] + internal object __DebugDisplay() => (object) ExtraTopLevelOperators.PrintFormatToString>((PrintfFormat, Unit, string, string>) new PrintfFormat, Unit, string, string, string>("%+0.8A")).Invoke(this); + + [CompilerGenerated] + public override string ToString() => ExtraTopLevelOperators.PrintFormatToString>((PrintfFormat, Unit, string, string>) new PrintfFormat, Unit, string, string, Program.IntOrBool>("%+A")).Invoke(this); + + [CompilerGenerated] + public virtual int CompareTo(Program.IntOrBool obj) + { + if (this != null) + { + if (obj == null) + return 1; + int num1 = !(this is Program.IntOrBool.B) ? 0 : 1; + int num2 = !(obj is Program.IntOrBool.B) ? 0 : 1; + if (num1 != num2) + return num1 - num2; + if (this is Program.IntOrBool.I) + { + Program.IntOrBool.I i1 = (Program.IntOrBool.I) this; + Program.IntOrBool.I i2 = (Program.IntOrBool.I) obj; + IComparer genericComparer = LanguagePrimitives.GenericComparer; + int num3 = i1.item; + int num4 = i2.item; + return num3 < num4 ? -1 : (num3 > num4 ? 1 : 0); + } + Program.IntOrBool.B b1 = (Program.IntOrBool.B) this; + Program.IntOrBool.B b2 = (Program.IntOrBool.B) obj; + IComparer genericComparer1 = LanguagePrimitives.GenericComparer; + bool flag1 = b1.item; + bool flag2 = b2.item; + return (flag1 ? 1 : 0) < (flag2 ? 1 : 0) ? -1 : ((flag1 ? 1 : 0) > (flag2 ? 1 : 0) ? 1 : 0); + } + return obj != null ? -1 : 0; + } + + [CompilerGenerated] + public virtual int CompareTo(object obj) => this.CompareTo((Program.IntOrBool) obj); + + [CompilerGenerated] + public virtual int CompareTo(object obj, IComparer comp) + { + Program.IntOrBool intOrBool = (Program.IntOrBool) obj; + if (this != null) + { + if ((Program.IntOrBool) obj == null) + return 1; + int num1 = !(this is Program.IntOrBool.B) ? 0 : 1; + int num2 = !(intOrBool is Program.IntOrBool.B) ? 0 : 1; + if (num1 != num2) + return num1 - num2; + if (this is Program.IntOrBool.I) + { + Program.IntOrBool.I i1 = (Program.IntOrBool.I) this; + Program.IntOrBool.I i2 = (Program.IntOrBool.I) intOrBool; + int num3 = i1.item; + int num4 = i2.item; + return num3 < num4 ? -1 : (num3 > num4 ? 1 : 0); + } + Program.IntOrBool.B b1 = (Program.IntOrBool.B) this; + Program.IntOrBool.B b2 = (Program.IntOrBool.B) intOrBool; + bool flag1 = b1.item; + bool flag2 = b2.item; + return (flag1 ? 1 : 0) < (flag2 ? 1 : 0) ? -1 : ((flag1 ? 1 : 0) > (flag2 ? 1 : 0) ? 1 : 0); + } + return (Program.IntOrBool) obj != null ? -1 : 0; + } + + [CompilerGenerated] + public virtual int GetHashCode(IEqualityComparer comp) + { + if (this == null) + return 0; + if (this is Program.IntOrBool.I) + { + Program.IntOrBool.I i = (Program.IntOrBool.I) this; + int num = 0; + return i.item + ((num << 6) + (num >> 2)) - 1640531527; + } + Program.IntOrBool.B b = (Program.IntOrBool.B) this; + int num1 = 1; + return (b.item ? 1 : 0) + ((num1 << 6) + (num1 >> 2)) - 1640531527; + } + + [CompilerGenerated] + public override sealed int GetHashCode() => this.GetHashCode(LanguagePrimitives.GenericEqualityComparer); + + [CompilerGenerated] + public virtual bool Equals(object obj, IEqualityComparer comp) + { + if (this == null) + return obj == null; + if (!(obj is Program.IntOrBool intOrBool) || (!(this is Program.IntOrBool.B) ? 0 : 1) != (!(intOrBool is Program.IntOrBool.B) ? 0 : 1)) + return false; + return this is Program.IntOrBool.I ? ((Program.IntOrBool.I) this).item == ((Program.IntOrBool.I) intOrBool).item : ((Program.IntOrBool.B) this).item == ((Program.IntOrBool.B) intOrBool).item; + } + + [CompilerGenerated] + public virtual bool Equals(Program.IntOrBool obj) + { + if (this == null) + return obj == null; + if (obj == null || (!(this is Program.IntOrBool.B) ? 0 : 1) != (!(obj is Program.IntOrBool.B) ? 0 : 1)) + return false; + return this is Program.IntOrBool.I ? ((Program.IntOrBool.I) this).item == ((Program.IntOrBool.I) obj).item : ((Program.IntOrBool.B) this).item == ((Program.IntOrBool.B) obj).item; + } + + [CompilerGenerated] + public override sealed bool Equals(object obj) => obj is Program.IntOrBool intOrBool && this.Equals(intOrBool); + + public static class Tags + { + public const int I = 0; + public const int B = 1; + } + + [DebuggerTypeProxy(typeof (Program.IntOrBool.I\u0040DebugTypeProxy))] + [DebuggerDisplay("{__DebugDisplay(),nq}")] + [Serializable] + [SpecialName] + public class I : Program.IntOrBool + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [CompilerGenerated] + [DebuggerNonUserCode] + internal readonly int item; + + [CompilerGenerated] + [DebuggerNonUserCode] + internal I(int item) => this.item = item; + + [CompilationMapping(SourceConstructFlags.Field, 0, 0)] + [CompilerGenerated] + [DebuggerNonUserCode] + public int Item + { + [DebuggerNonUserCode] get => this.item; + } + + [DebuggerNonUserCode] + public int get_Item() => this.item; + } + + [DebuggerTypeProxy(typeof (Program.IntOrBool.B\u0040DebugTypeProxy))] + [DebuggerDisplay("{__DebugDisplay(),nq}")] + [Serializable] + [SpecialName] + public class B : Program.IntOrBool + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [CompilerGenerated] + [DebuggerNonUserCode] + internal readonly bool item; + + [CompilerGenerated] + [DebuggerNonUserCode] + internal B(bool item) => this.item = item; + + [CompilationMapping(SourceConstructFlags.Field, 1, 0)] + [CompilerGenerated] + [DebuggerNonUserCode] + public bool Item + { + [DebuggerNonUserCode] get => this.item; + } + + [DebuggerNonUserCode] + public bool get_Item() => this.item; + } + + [SpecialName] + internal class I\u0040DebugTypeProxy + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [CompilerGenerated] + [DebuggerNonUserCode] + internal Program.IntOrBool.I _obj; + + [CompilerGenerated] + [DebuggerNonUserCode] + public I\u0040DebugTypeProxy(Program.IntOrBool.I obj) => this._obj = obj; + + [CompilationMapping(SourceConstructFlags.Field, 0, 0)] + [CompilerGenerated] + [DebuggerNonUserCode] + public int Item + { + [DebuggerNonUserCode] get => this._obj.item; + } + + [DebuggerNonUserCode] + public int get_Item() => this._obj.item; + } + + [SpecialName] + internal class B\u0040DebugTypeProxy + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [CompilerGenerated] + [DebuggerNonUserCode] + internal Program.IntOrBool.B _obj; + + [CompilerGenerated] + [DebuggerNonUserCode] + public B\u0040DebugTypeProxy(Program.IntOrBool.B obj) => this._obj = obj; + + [CompilationMapping(SourceConstructFlags.Field, 1, 0)] + [CompilerGenerated] + [DebuggerNonUserCode] + public bool Item + { + [DebuggerNonUserCode] get => this._obj.item; + } + + [DebuggerNonUserCode] + public bool get_Item() => this._obj.item; + } + } +} +``` diff --git a/TechLab1.md b/TechLab1.md new file mode 100644 index 0000000..c46bdf5 --- /dev/null +++ b/TechLab1.md @@ -0,0 +1,591 @@ +# TechLabs +## Лабораторная работа 1 +### Point 1 +```cpp +#include "pch.h" +#include "framework.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +#include + +extern "C" +{ + __declspec (dllexport) void __stdcall Java_MyClass_MyMethod() + { + std::cout << "Hello Java from C++"; + } + + __declspec (dllexport) void MyMethod() + { + std::cout << "Hello C# from C++"; + } +} +``` +Для начала, нужно создать срр файл и подключить dll библиотеку, а также перевести конфигурацию с Debug на Release. В конце исходника нужно написать extern "C", а внутри методы, которые мы хотим чтоб вызывались в Java и C#. "__declspec (dllexport)" - требование для каждого dll метода. Без этой приписки работать не будет. "__stdcall" - требование для Java, чтобы вызвать метод из dll. Лично у меня метод называется с припиской Java_"имя класса". В источнике, с которого я брал информацию, было сказано, что это тоже требование для вызова в Java, однако я знаю людей, у которых работало и без этого. В C# приписка "__stdcall" необязательна. + +#### Для работы с Java: +Нужно сбилдить проект и скопировать dll файл (не наш cpp файл, а именно dll) в проект в IDE, но только не внутрь src или каких-то других папок. Код в Java выглядит так: +```java +public class MyClass { + public native void MyMethod(); + + static + { + System.loadLibrary("Dll1"); + } + public static void main(String args[]) { + new MyClass().MyMethod(); + } +} +``` +Мы объявляем метод срр файла с модификатором native как раз для того, чтобы вызывать его из dll. Через System.loadLibrary("имя dll") загружаем библиотеку и в main вызываем метод. + +#### Для работы с C#: +Нужно сбилдить проект и скопировать путь на dll файл, затем импортировать dll: в DllImport указать этот путь и указать CallingConvention = Cdecl, иначе выкинется ошибка. У метода ставится модификатор extern (как в Java native). Код выглядит так: +```cs +using System; +using System.Runtime.InteropServices; + +namespace CPPInterop +{ + internal static class Program + { + private const string _dllPath = @"C:\Users\volok\source\repos\InteropCPP\x64\Release\Dll1"; + + [DllImport(_dllPath, CallingConvention = CallingConvention.Cdecl)] + + public static extern void MyMethod(); + + private static void Main() + { + MyMethod(); + } + } +} +``` + +Из сложностей работы с интеропом особо ничего не могу выделить - у меня проблем не было. Ограничений работы я тоже не увидел. +Источники информации: +https://www.youtube.com/watch?v=o-ass4mkdiA&t=0s +https://www.youtube.com/watch?v=41leCIAzSd0&t=0s + +### Point 2 +#### F# и декомпиляция в C#: +Код на F#: +```fs +let multi x y = x * y +let plus x y = x + y +type IntOrBool = + | I of int + | B of bool +let result x y z = multi x y |> plus z +let unionTrial x = + let i = I x + let b = B (x % 2 = 0) + printfn $"%d{x} + printfn $"{i} is odd?" + printfn $"{b}!" +``` +Честно, разбирался с Computation Expressions, но мало что понял, поэтому код очень простой и написан с использованием Pipe Operator и Discriminated Union. Его вызов в C#: +```cs +using System; + +namespace CSharpTesting +{ + internal static class Program + { + private static void Main() + { + var res = global::Program.result(1, 2, 3); + global::Program.unionTrial(res); + } + } +} +``` +Для вызова F# методов в C# требуется только вызвать их с global(и то, насколько я знаю, у некоторых работало и без него). Чтобы декомпилировать в C# я использовал dotPeek. +При декомпиляции в C# Discriminated Union превращается в абстрактный класс, и из-за этого код значительно раздувается. Сам код декомпиляции лежит в [SharpDecompiler.md](SharpDecompiler.md) +#### Scala и декомпиляция в Java: +Код на Scala: +```scala +import scala.util.chaining.scalaUtilChainingOps + +class ScalaTrial { + def multi(x : Int, y : Int): Int = x * y + def plus(x : Int, y : Int): Int = x + y + + def pipe() : Int = { + val x = 2.pipe(plus(_, 3)).pipe(multi(_, 2)) + x + } +} +``` +Что касается Scala, то, насколько я понял, там нет ни Discriminated Union, ни Computation Expressions, поэтому я написал максимально простой код с использованием .pipe(). Вызов кода в Java: +```java +public class JavaTesting { + public static void main(String[] args) { + ScalaTrial myObj = new ScalaTrial(); + int x = myObj.pipe(); + System.out.println(x); + } +} +``` +Как видно, ничего не мешает просто вызвать Scala метод в Java. Декомпилировал я с помощью View->Show Bytecode в IntelliJ. Код декомпиляции лежит в [JavaDecompiler.md](JavaDecompiler.md), и по факту декомпилятор просто подключил модуль Scala и использовал .pipe(). +### Point 3 +#### Работа с C# +DFS и BFS: +```cs +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CSharpGraphFs +{ + public class Graph + { + private int _V; + + private LinkedList[] _adj; + public Graph(int V) + { + _adj = new LinkedList[V]; + for(var i = 0; i < _adj.Length; i++) + { + _adj[i] = new LinkedList(); + } + _V = V; + } + + + public void AddEdge(int v, int w) + { + _adj[v].AddLast(w); + + } + + public void DFSUtil(int v, bool[] visited) + { + visited[v] = true; + Console.Write(v + " "); + var vList = _adj[v]; + foreach (var n in vList.Where(n => !visited[n])) + { + DFSUtil(n, visited); + } + } + + public void DFS(int v) + { + var visited = new bool[_V]; + DFSUtil(v, visited); + } + + public void BFS(int s) + { + + var visited = new bool[_V]; + for(var i = 0; i < _V; i++) + visited[i] = false; + + var queue = new LinkedList(); + visited[s] = true; + queue.AddLast(s); + + while(queue.Any()) + { + s = queue.First(); + Console.Write(s + " " ); + queue.RemoveFirst(); + var list = _adj[s]; + + foreach (var val in list.Where(val => !visited[val])) + { + visited[val] = true; + queue.AddLast(val); + } + } + } + } +} +``` +Собрать пакет можно с помощью NuGet. Для этого надо нажать пкм по проекту, выбрать Advanced Build Actions -> Pack Selected Project. После этого зайти в NuGet, нажать на sources, а затем New feed, а путь указать до Debug нашего проекта. Все готово, можно использовать пакет в другом проекте, добавив в начале using: +```cs +using CSharpGraphFs; + +namespace PackageUsing +{ + internal static class Program + { + private static void Main() + { + Graph graph = new Graph(6); + graph.AddEdge(0, 1); + graph.AddEdge(0, 2); + graph.AddEdge(1, 0); + graph.AddEdge(1, 3); + graph.AddEdge(2, 0); + graph.AddEdge(2, 3); + graph.AddEdge(3, 4); + graph.AddEdge(3, 5); + graph.AddEdge(4, 3); + graph.AddEdge(5, 3); + + graph.DFS(0); + Console.WriteLine('\n'); + graph.BFS(0); + } + } +} +``` +Для себя могу отметить сложность, которая у меня возникала: если обходы графа были изначально не совсем правильно написаны, а мы уже запаковали, то я не нашёл другого способа, кроме как пересоздать проект и запаковать заново. +#### Работа с Java +DFS и BFS: +```java +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Stack; + +public class JavaGraph { + int V; + + LinkedList[] adj; + + JavaGraph(int V) + { + this.V = V; + adj = new LinkedList[V]; + for (int i = 0; i < adj.length; i++) + adj[i] = new LinkedList(); + } + + void addEdge(int v, int w) + { + adj[v].add(w); + } + + void DFS(int n) + { + boolean[] nodes = new boolean[V]; + Stack stack = new Stack<>(); + stack.push(n); + int a = 0; + while(!stack.empty()) + { + n = stack.peek(); + stack.pop(); + if(!nodes[n]) + { + System.out.print(n + " "); + nodes[n] = true; + } + for (int i = 0; i < adj[n].size(); i++) + { + a = adj[n].get(i); + if (!nodes[a]) + { + stack.push(a); + } + } + } + } + + void BFS(int n) + { + boolean visited[] = new boolean[V]; + LinkedList queue = new LinkedList(); + visited[n]=true; + queue.add(n); + + while (queue.size() != 0) + { + n = queue.poll(); + System.out.print(n + " "); + Iterator i = adj[n].listIterator(); + while (i.hasNext()) + { + int next = i.next(); + if (!visited[next]) + { + visited[next] = true; + queue.add(next); + } + } + } + } +} +``` +С Java все немного сложнее. Лично я использовал Framework поддержку Maven и Groovy. Сначала с помощью Maven пакетируем проект, а потом нажимаем пкм по проекту -> Open Module Settings и добавляем в Libraries .jar файл, который создался, когда мы пакетировали проект (лежит в target). Все, пакет создался, можем его использовать: +```java +public class MyOwnMavenPackageTesting { + public static void main(String[] args) { + JavaGraph graph = new JavaGraph(6); + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(1, 0); + graph.addEdge(1, 3); + graph.addEdge(2, 0); + graph.addEdge(2, 3); + graph.addEdge(3, 4); + graph.addEdge(3, 5); + graph.addEdge(4, 3); + graph.addEdge(5, 3); + + graph.DFS(0); + System.out.println('\n'); + graph.BFS(0); + } +} +``` +При использовании пакета ничего добавлять не нужно, пакет используется автоматически. +### Point 4 +Я выбрал Gnome sort, Bubble sort и встроенную сортировку для анализа их работы с помощью Benchmark. +#### Работа с C# +Алгоритмы сортировок: +```cs +using System; +using BenchmarkDotNet.Attributes; + +namespace Benchmarks +{ + [MemoryDiagnoser] + public class Sorting + { + private const int Size = 10000; + + private readonly int[] _arr; + + public Sorting() + { + _arr = new int[Size]; + for (var i = 0; i < Size; i++) + { + _arr[i] = new Random().Next(); + } + } + + [Benchmark] + public int[] BubbleSort() + { + int temp; + var arr = _arr.ToArray(); + for (var i = 0; i < arr.Length; i++) + { + for (var j = i + 1; j < arr.Length; j++) + { + if (arr[i] <= arr[j]) continue; + temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + } + + return arr; + } + private void Swap(ref int item1, ref int item2) + { + (item1, item2) = (item2, item1); + } + + [Benchmark] + public int[] GnomeSort() + { + var index = 1; + var nextIndex = index + 1; + var arr = _arr.ToArray(); + while (index < arr.Length) + { + if (arr[index - 1] < arr[index]) + { + index = nextIndex; + nextIndex++; + } + else + { + Swap(ref arr[index - 1], ref arr[index]); + index--; + if (index != 0) continue; + index = nextIndex; + nextIndex++; + } + } + + return arr; + } + + [Benchmark] + public int[] BuiltInSort() + { + var arr = _arr.ToArray(); + Array.Sort(arr); + return arr; + } + + } +} +``` +Нам нужно установить BenchmarkDotNet NuGet пакет. Затем для анализа аллокации памяти добавить атрибут "MemoryDiagnoser" перед объявлением класса, а для анализа времени выполнения добавить атрибут "Benchmark" до каждого определения функции. Код выполнения Benchmark: +```cs +using BenchmarkDotNet.Reports; +using BenchmarkDotNet.Running; + +namespace Benchmarks +{ + internal static class Program + { + private static void Main() + { + var summary = BenchmarkRunner.Run(); + } + } +} +``` +Результат выполнения:\ +![image](https://user-images.githubusercontent.com/79001610/156830279-ae95ce74-8fa2-45d8-b640-fde9382e8c60.png)\ +Как и ожидалось, bubble sort отработала медленней всех, а встроенная быстрее всех, при этом память выделяется почти одинаково во всех алгоритмах. +#### Работа с Java +Алгоритмы сортировок: +```java +package com.Benchmarks; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +@Fork(value = 2, jvmArgs = {"-Xms2G", "-Xmx2G"}) +public class Sorting { + + @Param({"10000"}) + private int Size; + + private int[] _arr; + + public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } + + public Sorting() + { + _arr = new int[Size]; + for (var i = 0; i < Size; i++) + { + _arr[i] = (int) (Math.random() * 10000); + } + } + + @org.openjdk.jmh.annotations.Benchmark + @Fork(value = 1, warmups = 1) + @Warmup(iterations = 2) + public int[] BubbleSort() + { + var arr = _arr; + for (int i = 0; i < arr.length - 1; i++) { + for (int j = 0; j < arr.length - i - 1; j++) + if (arr[j] > arr[j + 1]) { + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + + return arr; + } + + @org.openjdk.jmh.annotations.Benchmark + @Fork(value = 1, warmups = 1) + @Warmup(iterations = 2) + public int[] GnomeSort() + { + int index = 0; + var arr = _arr; + while (index < arr.length) { + if (index == 0) + index++; + if (arr[index] >= arr[index - 1]) + index++; + else { + int temp = 0; + temp = arr[index]; + arr[index] = arr[index - 1]; + arr[index - 1] = temp; + index--; + } + } + return arr; + } + + @org.openjdk.jmh.annotations.Benchmark + @Fork(value = 1, warmups = 1) + @Warmup(iterations = 2) + public int[] BuiltInSort() + { + var arr = _arr; + Arrays.sort(arr); + return arr; + } +} +``` +В Java JMH работает крайне сложно и неприятно. Для начала запустить Maven и открыть pom файл, туда добавить зависимостей: +```xml + + + org.openjdk.jmh + jmh-core + 1.33 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.33 + + +``` +Затем в Maven обновить все проекты. Касаемо алгоритмов сортировок: лично я добавил +```java +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +@Fork(value = 2, jvmArgs = {"-Xms2G", "-Xmx2G"}) +``` +до объявления класса, а перед каждым алгоритмом добавлял вот это: +```java +@org.openjdk.jmh.annotations.Benchmark +@Fork(value = 1, warmups = 1) +@Warmup(iterations = 2) +``` +Затем надо запустить JMH: +```java +public static void main(String[] args) throws Exception { + org.openjdk.jmh.Main.main(args); + } +``` +Некоторые из атрибутов опциональны и нужны просто для большей информации.\ +Результат работы:\ +![image](https://user-images.githubusercontent.com/79001610/156833698-8e0fd4c4-24cb-4283-8190-6ee699d3ce75.png)\ +Очень странно получилось, но почему-то в Java получилось всё наоборот, скорость bubble sort самая большая, а встроенная самая медленная (по количеству операций в наносекунду). +Источники: https://mkyong.com/java/java-jmh-benchmark-tutorial/ +### Point 5 +Для анализа я использовал dotMemory.\ +С файловой системой:\ +![image](https://user-images.githubusercontent.com/79001610/156853257-5195520c-b8b6-4dd5-8450-052de1b28928.png)\ +Не с файловой системой:\ +![image](https://user-images.githubusercontent.com/79001610/156853438-42919d60-4b0c-4c2e-b94f-d89e8286e319.png)\ +Почему-то получились абсолютно одинаковые результаты, хотя с файловой системой сборщик мусора начинает удалять точки, и общая картина должна выглядеть примерно как зубы акулы, но этого не происходит - странно.