ronantakizawa/codereview-bench huggingface dataset:
Repository: Arriven/db1000n
File: src/utils/ota/ota.go (Go)

Code before:
// Package ota [allows hot update and reload of the executable]
package ota

import (
	"github.com/blang/semver"
	"github.com/pkg/errors"
	"github.com/rhysd/go-github-selfupdate/selfupdate"
)

// DoAutoUpdate updates the app to the latest version.
func DoAutoUpdate() (updateFound bool, newVersion, changeLog string, err error) {
	v, err := semver.ParseTolerant(Version)
	if err != nil {
		err = errors.Wrap(err, "binary version validation failed")
		return
	}

	latest, err := selfupdate.UpdateSelf(v, Repository)
	if err != nil {
		err = errors.Wrap(err, "binary update failed")
		return
	}

	if !latest.Version.Equals(v) {
		updateFound = true
		newVersion = latest.Version.String()
		changeLog = latest.ReleaseNotes
	}

	return
}

func MockAutoUpdate(shouldUpdateBeFound bool) (updateFound bool, newVersion, changeLog string, err error) {
	updateFound = shouldUpdateBeFound
	if updateFound {
		newVersion = "brand-new-version"
		changeLog = "something-was-changed"
		err = nil
	}

Review comment (performance):
Please use fmt.Errorf here, no need to import additional dependency just to wrap errors (even if it's faster - this is not a hot path)

Code after:
// Package ota [allows hot update and reload of the executable]
package ota

import (
	"fmt"

	"github.com/blang/semver"
	"github.com/rhysd/go-github-selfupdate/selfupdate"
)

// DoAutoUpdate updates the app to the latest version.
func DoAutoUpdate() (updateFound bool, newVersion, changeLog string, err error) {
	v, err := semver.ParseTolerant(Version)
	if err != nil {
		err = fmt.Errorf("binary version validation failed: %w", err)

		return
	}

	latest, err := selfupdate.UpdateSelf(v, Repository)
	if err != nil {
		err = fmt.Errorf("binary update failed: %w", err)

		return
	}

	if !latest.Version.Equals(v) {
		updateFound = true
		newVersion = latest.Version.String()
		changeLog = latest.ReleaseNotes
	}

	return
}

func MockAutoUpdate(shouldUpdateBeFound bool) (updateFound bool, newVersion, changeLog string, err error) {
	updateFound = shouldUpdateBeFound
	if updateFound {
		newVersion = "brand-new-version"
Repository: Arriven/db1000n
File: src/core/dnsblast/qry/types.go (Go)

Code before:
package qry

import "github.com/miekg/dns"

// ResponseCode convert numerical response code value to string
func ResponseCode(rc int) string {
	rcodes := map[int]string{
		0: "NOERROR",
		1: "FORMERR",
		2: "SERVFAIL",
		3: "NXDOMAIN",
		4: "NOTIMP",
		5: "REFUSED",
		6: "YXDOMAIN",
		7: "YXRRSET",
		8: "NOTAUTH",
		9: "NOTZONE",
	}

	return rcodes[rc]
}

// Qtype is used to conver string representation of query type into proper dns format
func Qtype(qt string) uint16 {
	res, ok := map[string]uint16{
		"None":       dns.TypeNone,
		"A":          dns.TypeA,
		"NS":         dns.TypeNS,
		"MD":         dns.TypeMD,
		"MF":         dns.TypeMF,
		"CNAME":      dns.TypeCNAME,
		"SOA":        dns.TypeSOA,
		"MB":         dns.TypeMB,
		"MG":         dns.TypeMG,
		"MR":         dns.TypeMR,
		"NULL":       dns.TypeNULL,
		"PTR":        dns.TypePTR,
		"HINFO":      dns.TypeHINFO,
		"MINFO":      dns.TypeMINFO,
		"MX":         dns.TypeMX,
		"TXT":        dns.TypeTXT,
		"RP":         dns.TypeRP,
		"AFSDB":      dns.TypeAFSDB,
		"X25":        dns.TypeX25,
		"ISDN":       dns.TypeISDN,
		"RT":         dns.TypeRT,
		"NSAPPTR":    dns.TypeNSAPPTR,
		"SIG":        dns.TypeSIG,
		"KEY":        dns.TypeKEY,
		"PX":         dns.TypePX,
		"GPOS":       dns.TypeGPOS,

Review comment (performance):
Does cyclop bitch about switch because it thinks of each case as a separate branch? Also are we sure that the map is optimized away by the compiler? (I assume it's yes for both cases but better be safe than sorry)

Code after:
package qry

import "github.com/miekg/dns"

// ResponseCode convert numerical response code value to string
func ResponseCode(rc int) string {
	rcodes := map[int]string{
		0: "NOERROR",
		1: "FORMERR",
		2: "SERVFAIL",
		3: "NXDOMAIN",
		4: "NOTIMP",
		5: "REFUSED",
		6: "YXDOMAIN",
		7: "YXRRSET",
		8: "NOTAUTH",
		9: "NOTZONE",
	}

	return rcodes[rc]
}

// Qtype is used to conver string representation of query type into proper dns format
//nolint:cyclop // The string map alternative is orders of magnitude slower
func Qtype(qt string) uint16 {
	switch qt {
	case "None":
		return dns.TypeNone
	case "A":
		return dns.TypeA
	case "NS":
		return dns.TypeNS
	case "MD":
		return dns.TypeMD
	case "MF":
		return dns.TypeMF
	case "CNAME":
		return dns.TypeCNAME
	case "SOA":
		return dns.TypeSOA
	case "MB":
		return dns.TypeMB
	case "MG":
		return dns.TypeMG
	case "MR":
		return dns.TypeMR
	case "NULL":
		return dns.TypeNULL
	case "PTR":
		return dns.TypePTR
	case "HINFO":
Repository: Arriven/db1000n
File: src/utils/metrics/reporter.go (Go)

Code before:

func (r *ConsoleReporter) WriteSummary(metrics *Metrics) {
	w := tabwriter.NewWriter(r.target, 1, 1, 1, ' ', tabwriter.AlignRight)

	defer w.Flush()

	stats, totals := metrics.SumAllStats()

	fmt.Fprintln(w, "\n --- Traffic stats ---")
	fmt.Fprintf(w, "|\tTarget\t|\tRequests attempted\t|\tRequests sent\t|\tResponses received\t|\tData sent \t|\n")

	const BytesInMegabyte = 1024 * 1024

	for _, tgt := range stats.sortedTargets() {
		tgtStats := stats[tgt]

		fmt.Fprintf(w, "|\t%s\t|\t%d\t|\t%d\t|\t%d\t|\t%.2f MB \t|\n", tgt,
			tgtStats[RequestsAttemptedStat],
			tgtStats[RequestsSentStat],
			tgtStats[ResponsesReceivedStat],
			float64(tgtStats[BytesSentStat])/BytesInMegabyte,
		)

		for s := range totals {
			totals[s] += tgtStats[s]
		}
	}

	fmt.Fprintln(w, "|\t---\t|\t---\t|\t---\t|\t---\t|\t--- \t|")
	fmt.Fprintf(w, "|\tTotal\t|\t%d\t|\t%d\t|\t%d\t|\t%.2f MB \t|\n\n",
		totals[RequestsAttemptedStat],
		totals[RequestsSentStat],
		totals[ResponsesReceivedStat],
		float64(totals[BytesSentStat])/BytesInMegabyte,
	)
}


Review comment (suggestion):
this was the actual loop which doubled the total stats - now all calculations are done by `stats, totals := metrics.SumAllStats()` call and there is no need for reporters to calculate anything

Code after:

func (r *ConsoleReporter) WriteSummary(metrics *Metrics) {
	writer := tabwriter.NewWriter(r.target, 1, 1, 1, ' ', tabwriter.AlignRight)
	stats, totals := metrics.SumAllStats()

	defer writer.Flush()

	// Print table's header
	fmt.Fprintln(writer, "\n --- Traffic stats ---")
	fmt.Fprintf(writer, "|\tTarget\t|\tRequests attempted\t|\tRequests sent\t|\tResponses received\t|\tData sent \t|\n")

	// Print all table rows
	for _, tgt := range stats.sortedTargets() {
		printStatsRow(writer, tgt, stats[tgt])
	}

	// Print table's footer
	fmt.Fprintln(writer, "|\t---\t|\t---\t|\t---\t|\t---\t|\t--- \t|")
	printStatsRow(writer, "Total", totals)
	fmt.Fprintln(writer)
}

func printStatsRow(writer *tabwriter.Writer, rowName string, stats Stats) {
	const BytesInMegabyte = 1024 * 1024

	fmt.Fprintf(writer, "|\t%s\t|\t%d\t|\t%d\t|\t%d\t|\t%.2f MB \t|\n", rowName,
		stats[RequestsAttemptedStat],
		stats[RequestsSentStat],
		stats[ResponsesReceivedStat],
		float64(stats[BytesSentStat])/BytesInMegabyte,
	)
}
Repository: Baekalfen/PyBoy
File: pyboy/utils.py (Python)

Code before:
    """
    bcd_result = []
    for _ in range(byte_width):
        tens = ((value%100) // 10) << 4
        units = value % 10
        bcd_byte = (tens | units) & 0xFF
        bcd_result.append(bcd_byte)
        value //= 100
    return int.from_bytes(bcd_result, byteorder)


def bcd_to_dec(value, byte_width=1, byteorder="little"):
    """
    Converts a Binary Coded Decimal (BCD) value to decimal.

    :param value: BCD value to convert.
    :param byte_width: The number of bytes to consider for each value.
    :param byteorder: The endian type to use (see [int.to_bytes](https://docs.python.org/3/library/stdtypes.html#int.to_bytes)). Note, this is only used for 16-bit values and higher.
    :return: Decimal equivalent of the BCD value.
    """
    decimal_value = 0
    multiplier = 1

    bcd_bytes = value.to_bytes(byte_width, byteorder)

    for bcd_byte in bcd_bytes:
        decimal_value += ((bcd_byte >> 4) * 10 + (bcd_byte & 0x0F)) * multiplier
        multiplier *= 100

    return decimal_value


Review comment (suggestion):
The docs generator we're using doesn't pick up this format. You can see `pyboy.py` for examples on how to format it.

Code after:

    Returns:
        int: The BCD equivalent of the decimal value.
    """
    bcd_result = []
    for _ in range(byte_width):
        tens = ((value%100) // 10) << 4
        units = value % 10
        bcd_byte = (tens | units) & 0xFF
        bcd_result.append(bcd_byte)
        value //= 100
    return int.from_bytes(bcd_result, byteorder)


def bcd_to_dec(value, byte_width=1, byteorder="little"):
    """
    Converts a Binary Coded Decimal (BCD) value to decimal.

    Args:
        value (int): The BCD value to convert.
        byte_width (int): The number of bytes to consider for each value.
        byteorder (str): The endian type to use. This is only used for 16-bit values and higher. See [int.to_bytes](https://docs.python.org/3/library/stdtypes.html#int.to_bytes) for more details.

    Returns:
        int: The decimal equivalent of the BCD value.
    """
    decimal_value = 0
    multiplier = 1

    bcd_bytes = value.to_bytes(byte_width, byteorder)

    for bcd_byte in bcd_bytes:
        decimal_value += ((bcd_byte >> 4) * 10 + (bcd_byte & 0x0F)) * multiplier
        multiplier *= 100

    return decimal_value
Repository: ClemensElflein/OpenMower
File: Firmware/LowLevel/lib/JY901_SERIAL/JY901.cpp (C++)

Code before:
#include "JY901.h"
#include "string.h"

#ifdef WT901_INSTEAD_OF_SOUND
CJY901 ::CJY901(HardwareSerial *serial)
#elif WT901
CJY901 ::CJY901(SerialPIO *serial)
#endif
{
	this->serial = serial;
}

void CJY901::begin(unsigned long baudrate) {
	serial->begin(baudrate);
	delay(1000);
	/*uint8_t unlock[] = {0xFF,0xF0,0xF0,0xF0,0xF0}; // undocumented / unknown?
	serial->write(unlock, 5);
	serial->flush();
	delay(10);*/
	writeRegister(RSW, 0b0000000000010110);  // Return data content
	delay(10);
	writeRegister(RRATE, 0x08); // Return rate 0x06 = 10Hz (default), 0x08 = 50Hz, 0x09 = 100Hz
	delay(10);
	writeRegister(0x0b, 0x00);  // X axis Magnetic bias
	delay(10);
	writeRegister(0x0c, 0x00);  // Y axis Magnetic bias
	delay(10);
	writeRegister(0x0d, 0x00);  // Z axis Magnetic bias
	delay(10);

	ucRxCnt = 0;
}

void CJY901 ::update()
{
	while (serial->available())
	{

		ucRxBuffer[ucRxCnt++] = serial->read();
		if (ucRxBuffer[0] != 0x55)
		{

Review comment (suggestion):
Couldn't find this unlock code in any documentation. Only in a doubtful Amazon comment. So I disabled it.

Code after:
#include "JY901.h"
#include "string.h"

#ifdef WT901_INSTEAD_OF_SOUND
CJY901 ::CJY901(HardwareSerial *serial)
#elif WT901
CJY901 ::CJY901(SerialPIO *serial)
#endif
{
	this->serial = serial;
}

void CJY901::begin(unsigned long baudrate) {
	serial->begin(baudrate);
	delay(1000);
	uint8_t unlock[] = {0xFF,0xF0,0xF0,0xF0,0xF0}; // undocumented but required magic unlock sequence
	serial->write(unlock, 5);
	serial->flush();
	delay(10);
	writeRegister(RSW, 0b0000000000010110);  // Return data content
	delay(10);
	writeRegister(RRATE, 0x08); // Return rate 0x06 = 10Hz (default), 0x08 = 50Hz, 0x09 = 100Hz
	delay(10);
	writeRegister(0x0b, 0x00);  // X axis Magnetic bias
	delay(10);
	writeRegister(0x0c, 0x00);  // Y axis Magnetic bias
	delay(10);
	writeRegister(0x0d, 0x00);  // Z axis Magnetic bias
	delay(10);

	ucRxCnt = 0;
}

void CJY901 ::update()
{
	while (serial->available())
	{

		ucRxBuffer[ucRxCnt++] = serial->read();
		if (ucRxBuffer[0] != 0x55)
		{
Repository: ClemensElflein/OpenMower
File: Firmware/LowLevel/src/main.cpp (C++)

Code before:
                break;
            case 6:
                mutex_enter_blocking(&mtx_status_message);
                if (state) {
                    status_message.status_bitmask |= 0b01000000;
                } else {
                    status_message.status_bitmask &= 0b10111111;
                }
                mutex_exit(&mtx_status_message);
                break;
            default:
                break;
        }
    }

    delay(100);
}

void setup() {
    //  We do hardware init in this core, so that we don't get invalid states.
    //  Therefore, we pause the other core until setup() was a success
    rp2040.idleOtherCore();

#ifdef USB_DEBUG
    DEBUG_BEGIN(9600);
#endif

    emergency_latch = true;
    ROS_running = false;

    lift_emergency_started = 0;
    button_emergency_started = 0;
    // Initialize messages
    imu_message = {0};
    status_message = {0};
    imu_message.type = PACKET_ID_LL_IMU;
    status_message.type = PACKET_ID_LL_STATUS;

    // Setup pins
    pinMode(LED_BUILTIN, OUTPUT);
    pinMode(PIN_ENABLE_CHARGE, OUTPUT);
    digitalWrite(PIN_ENABLE_CHARGE, HIGH);

    gpio_init(PIN_RASPI_POWER);
    gpio_put(PIN_RASPI_POWER, true);
    gpio_set_dir(PIN_RASPI_POWER, true);
    gpio_put(PIN_RASPI_POWER, true);

    // Enable raspi power
    p.neoPixelSetValue(0, 32, 0, 0, true);
    delay(1000);

Review comment (bug):
Nit-picking here, but I think you can just always call DEBUG_BEGIN, should be a no-op for non-debug (and I think you even had a comment about that in debug.h 😉).

Code after:

        switch (mux_address) {
            case 5:
                mutex_enter_blocking(&mtx_status_message);

                if (state || stock_ui_rain) {
                    status_message.status_bitmask |= 0b00010000;
                } else {
                    status_message.status_bitmask &= 0b11101111;
                }
                mutex_exit(&mtx_status_message);

                break;
            case 6:
                mutex_enter_blocking(&mtx_status_message);
                if (state) {
                    status_message.status_bitmask |= 0b01000000;
                } else {
                    status_message.status_bitmask &= 0b10111111;
                }
                mutex_exit(&mtx_status_message);
                break;
            default:
                break;
        }
    }

    delay(100);
}

void setup() {
    //  We do hardware init in this core, so that we don't get invalid states.
    //  Therefore, we pause the other core until setup() was a success
    rp2040.idleOtherCore();

#ifdef USB_DEBUG
    DEBUG_SERIAL.begin(9600);
#endif

    emergency_latch = true;
    ROS_running = false;

    lift_emergency_started = 0;
    button_emergency_started = 0;
    // Initialize messages
    imu_message = {0};
    status_message = {0};
    imu_message.type = PACKET_ID_LL_IMU;
    status_message.type = PACKET_ID_LL_STATUS;

    // Setup pins
Repository: FlaxEngine/FlaxEngine
File: Source/Editor/Editor.cpp (C++)

Code before:
        }
        else
        {
            window->SetIcon(icon);
        }
    }
    else
    {
        LOG(Warning, "Missing icon file.");
    }
#endif
    return window;
}

bool Editor::Init()
{
    // Scripts project files generation from command line
    if (CommandLine::Options.GenProjectFiles)
    {
        const bool failed = ScriptsBuilder::GenerateProject();
        exit(failed ? 1 : 0);
        return true;
    }

    // Skip compilation if play on start
    if (CommandLine::Options.Game.HasValue())
    {
        CommandLine::Options.SkipCompile.SetValue(true);
    }
    
    // If during last lightmaps baking engine crashed we could try to restore the progress
    ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();

    Engine::Update.Bind(&EditorImpl::OnUpdate);
    Managed = New<ManagedEditor>();

    // Show splash screen
    if (EditorImpl::Splash == nullptr)
        EditorImpl::Splash = New<SplashScreen>();
    EditorImpl::Splash->SetTitle(Project->Name);
    EditorImpl::Splash->Show();

    // Initialize managed editor
    Managed->Init();

    // Start play if requested by cmd line
    if (CommandLine::Options.Game.HasValue())
    {
        Managed->RequestStartPlayOnEditMode();
    }
    

Review comment (bug):
Does it work without compilation skipping? Because devs can already use `-skipcompile` arg (added by default to C++ projects debug cmd line) or disable initial compilation in Editor options.

Code after:
        }
        else
        {
            window->SetIcon(icon);
        }
    }
    else
    {
        LOG(Warning, "Missing icon file.");
    }
#endif
    return window;
}

bool Editor::Init()
{
    // Scripts project files generation from command line
    if (CommandLine::Options.GenProjectFiles)
    {
        const bool failed = ScriptsBuilder::GenerateProject();
        exit(failed ? 1 : 0);
        return true;
    }
    
    // If during last lightmaps baking engine crashed we could try to restore the progress
    ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();

    Engine::Update.Bind(&EditorImpl::OnUpdate);
    Managed = New<ManagedEditor>();

    // Show splash screen
    if (EditorImpl::Splash == nullptr)
        EditorImpl::Splash = New<SplashScreen>();
    EditorImpl::Splash->SetTitle(Project->Name);
    EditorImpl::Splash->Show();

    // Initialize managed editor
    Managed->Init();

    // Start play if requested by cmd line
    if (CommandLine::Options.Play.HasValue())
    {
        Managed->RequestStartPlayOnEditMode();
    }
    
    return false;
}

void Editor::BeforeRun()
{
    // If during last lightmaps baking engine crashed we could try to restore the progress
Repository: FlaxEngine/FlaxEngine
File: Source/Engine/Platform/Windows/WindowsClipboard.cpp (C++)

Code before:
#if PLATFORM_WINDOWS

#include "WindowsClipboard.h"
#include "Engine/Core/Collections/Array.h"
#include "../Win32/IncludeWindowsHeaders.h"

typedef struct _DROPFILES
{
    DWORD pFiles;
    POINT pt;
    BOOL fNC;
    BOOL fWide;
} DROPFILES, *LPDROPFILES;

void WindowsClipboard::Clear()
{
    OpenClipboard(nullptr);
    EmptyClipboard();
    CloseClipboard();
}

void WindowsClipboard::SetText(const StringView& text)
{
    const int32 size = (text.Length() + 1) * sizeof(Char);
    const HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, size);
    Platform::MemoryCopy(GlobalLock(hMem), String(text).GetText(), size);
    GlobalUnlock(hMem);

    OpenClipboard(nullptr);
    EmptyClipboard();
    SetClipboardData(CF_UNICODETEXT, hMem);
    CloseClipboard();
}

void WindowsClipboard::SetRawData(const Span<byte>& data)
{
    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, data.Length());
    Platform::MemoryCopy(GlobalLock(hMem), data.Get(), data.Length());
    GlobalUnlock(hMem);

    OpenClipboard(nullptr);
    EmptyClipboard();
    SetClipboardData(CF_PENDATA, hMem);
    CloseClipboard();
}

void WindowsClipboard::SetFiles(const Array<String>& files)
{
    int32 size = sizeof(DROPFILES);
    for (int32 i = 0; i < files.Count(); i++)
    {

Review comment (performance):
If text to copy is large then allocating it into memory might be slower. Maybe we could do separate copy for text and manually insert null-terminator in the end?

Code after:
#if PLATFORM_WINDOWS

#include "WindowsClipboard.h"
#include "Engine/Core/Collections/Array.h"
#include "../Win32/IncludeWindowsHeaders.h"

typedef struct _DROPFILES
{
    DWORD pFiles;
    POINT pt;
    BOOL fNC;
    BOOL fWide;
} DROPFILES, *LPDROPFILES;

void WindowsClipboard::Clear()
{
    OpenClipboard(nullptr);
    EmptyClipboard();
    CloseClipboard();
}

void WindowsClipboard::SetText(const StringView& text)
{
    const int32 sizeWithoutNull = text.Length() * sizeof(Char);
    const HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, sizeWithoutNull + sizeof(Char));

    Char* pMem = static_cast<Char*>(GlobalLock(hMem));
    Platform::MemoryCopy(pMem, text.GetNonTerminatedText(), sizeWithoutNull);
    Platform::MemorySet(pMem + text.Length(), sizeof(Char), 0);
    GlobalUnlock(hMem);

    OpenClipboard(nullptr);
    EmptyClipboard();
    SetClipboardData(CF_UNICODETEXT, hMem);
    CloseClipboard();
}

void WindowsClipboard::SetRawData(const Span<byte>& data)
{
    HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, data.Length());
    Platform::MemoryCopy(GlobalLock(hMem), data.Get(), data.Length());
    GlobalUnlock(hMem);

    OpenClipboard(nullptr);
    EmptyClipboard();
    SetClipboardData(CF_PENDATA, hMem);
    CloseClipboard();
}

void WindowsClipboard::SetFiles(const Array<String>& files)
{
Repository: FlaxEngine/FlaxEngine
File: Source/Engine/Threading/JobSystem.cpp (C++)

Code before:
            JobsMutex.Lock();
            JobsSignal.Wait(JobsMutex);
            JobsMutex.Unlock();
        }
    }
    return 0;
}

#endif

int64 JobSystem::Dispatch(const Function<void(int32)>& job, int32 jobCount)
{
    PROFILE_CPU();
    if (jobCount <= 0)
        return 0;
#if JOB_SYSTEM_ENABLED
#if JOB_SYSTEM_USE_STATS
    const auto start = Platform::GetTimeCycles();
#endif
    const auto label = Platform::InterlockedAdd(&JobLabel, (int64)jobCount) + jobCount;

    JobData data;
    data.Job = job;
    data.JobKey = label;

    auto context = New<JobContext>();
    context->JobCount = jobCount;

    JobContextMutex.Lock();
    JobContexts.Add(label, context);
    JobContextMutex.Unlock();

#if JOB_SYSTEM_USE_MUTEX
    JobsLocker.Lock();
    for (data.Index = 0; data.Index < jobCount; data.Index++)
        Jobs.PushBack(data);
    JobsLocker.Unlock();
#else
    for (data.Index = 0; data.Index < jobCount; data.Index++)
        Jobs.enqueue(data);
#endif

#if JOB_SYSTEM_USE_STATS
    LOG(Info, "Job enqueue time: {0} cycles", (int64)(Platform::GetTimeCycles() - start));
#endif

    if (JobStartingOnDispatch)
    {
        if (jobCount == 1)
            JobsSignal.NotifyOne();
        else

Review comment (suggestion):
Could we skip memory dynamic allocations or just reuse them from jobs contexts pool (eg. 8?)

Code after:
            JobsMutex.Unlock();
        }
    }
    return 0;
}

#endif

int64 JobSystem::Dispatch(const Function<void(int32)>& job, int32 jobCount)
{
    PROFILE_CPU();
    if (jobCount <= 0)
        return 0;
#if JOB_SYSTEM_ENABLED
#if JOB_SYSTEM_USE_STATS
    const auto start = Platform::GetTimeCycles();
#endif
    const auto label = Platform::InterlockedAdd(&JobLabel, (int64)jobCount) + jobCount;

    JobData data;
    data.Job = job;
    data.JobKey = label;

    // Allocate dynamically in case the dictionary gets reallocated
    JobContext* context = New<JobContext>();
    context->JobsLeft = jobCount;
    Platform::InterlockedIncrement(&context->RefCount);

    JobContextMutex.Lock();
    JobContexts.Add(label, context);
    JobContextMutex.Unlock();

#if JOB_SYSTEM_USE_MUTEX
    JobsLocker.Lock();
    for (data.Index = 0; data.Index < jobCount; data.Index++)
        Jobs.PushBack(data);
    JobsLocker.Unlock();
#else
    for (data.Index = 0; data.Index < jobCount; data.Index++)
        Jobs.enqueue(data);
#endif

#if JOB_SYSTEM_USE_STATS
    LOG(Info, "Job enqueue time: {0} cycles", (int64)(Platform::GetTimeCycles() - start));
#endif

    if (JobStartingOnDispatch)
    {
        if (jobCount == 1)
            JobsSignal.NotifyOne();
        else