text:
/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/

#include "mitkCommandLineParser.h"
#include "mitkImage.h"
#include <mitkImageStatisticsCalculator.h>
#include <mitkExtendedLabelStatisticsImageFilter.h>
#include <mitkPlanarFigureMaskGenerator.h>
#include <mitkPlanarFigure.h>
#include "mitkIOUtil.h"
#include <iostream>
#include <usAny.h>
#include <fstream>
#include <itkImageRegionConstIterator.h>
#include "mitkImageAccessByItk.h"
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/mean.hpp>
#include <boost/accumulators/statistics/variance.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/count.hpp>
#include <boost/accumulators/statistics/moment.hpp>
#include <mitkImageMaskGenerator.h>
#include <mitkHotspotMaskGenerator.h>
#include <mitkIgnorePixelMaskGenerator.h>
#include <chrono>

struct statistics_res{
    double mean, variance, min, max, count, moment;
};

long getTimeInMs()
{
    std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds > (std::chrono::system_clock::now().time_since_epoch());
    long time = ms.count();
    return time;
}

//std::string printstats(mitk::ImageStatisticsCalculator::Statistics statisticsStruct)
//{
//   std::string res = "";
//   res += std::string("Entropy ") + std::to_string(statisticsStruct.GetEntropy()) + std::string("\n");
//   res += std::string("Kurtosis ") + std::to_string(statisticsStruct.GetKurtosis()) + std::string("\n");
//   res += std::string("MPP ") + std::to_string(statisticsStruct.GetMPP()) + std::string("\n");
//   res += std::string("Max ") + std::to_string(statisticsStruct.GetMax()) + std::string("\n");
//   res += std::string("Mean ") + std::to_string(statisticsStruct.GetMean()) + std::string("\n");
//   res += std::string("Median ") + std::to_string(statisticsStruct.GetMedian()) + std::string("\n");
//   res += std::string("Min ") + std::to_string(statisticsStruct.GetMin()) + std::string("\n");
//   res += std::string("N ") + std::to_string(statisticsStruct.GetN()) + std::string("\n");
//   res += std::string("RMS ") + std::to_string(statisticsStruct.GetRMS()) + std::string("\n");
//   res += std::string("Skewness ") + std::to_string(statisticsStruct.GetSkewness()) + std::string("\n");
//   res += std::string("Std ") + std::to_string(statisticsStruct.GetSigma()) + std::string("\n");
//   res += std::string("UPP ") + std::to_string(statisticsStruct.GetUPP()) + std::string("\n");
//   res += std::string("Uniformity ") + std::to_string(statisticsStruct.GetUniformity()) + std::string("\n");
//   res += std::string("Variance ") + std::to_string(statisticsStruct.GetVariance()) + std::string("\n");
//   vnl_vector<int> minIndex = statisticsStruct.GetMinIndex();
//   vnl_vector<int> maxIndex = statisticsStruct.GetMaxIndex();

//   res += "Min Index:  ";
//   for (auto it = minIndex.begin(); it != minIndex.end(); it++)
//   {
//       res += std::to_string(*it) + " ";
//   }
//   res += std::string("\n");

//   res += "Max Index:  ";
//   for (auto it = maxIndex.begin(); it != maxIndex.end(); it++)
//   {
//       res += std::to_string(*it) + " ";
//   }
//   res += std::string("\n");
//   return res;
//}

template <class T, class P>
void printMap(std::map<T, P> input)
{
    for (auto it = input.begin(); it != input.end(); ++it)
    {
        std::cout << it->first<< ": " << it->second<< std::endl;
    }
    std::cout << std::endl;
}

template < typename TPixel, unsigned int VImageDimension >
void get_statistics_boost(itk::Image<TPixel, VImageDimension>* itkImage, statistics_res& res){
    typedef itk::Image<TPixel, VImageDimension> ImageType;

    itk::ImageRegionConstIterator<ImageType> it(itkImage, itkImage->GetLargestPossibleRegion());

    int ctr=0;
    double sum=0;

    boost::accumulators::accumulator_set<double, boost::accumulators::stats<
            boost::accumulators::tag::mean,
            boost::accumulators::tag::variance,
            boost::accumulators::tag::min,
            boost::accumulators::tag::max,
            boost::accumulators::tag::count,
            boost::accumulators::tag::moment<2>> > acc;

    for (it.GoToBegin(); !it.IsAtEnd(); ++it)
    {
        acc(it.Get());
//        currentPixel = it.Get();
//        sum+=currentPixel;
//        ctr+=1;
    }

//    res.mean=(double)sum/(double)ctr;
    res.mean = boost::accumulators::mean(acc);
    res.variance = boost::accumulators::variance(acc);
    res.min = boost::accumulators::min(acc);
    res.max = boost::accumulators::max(acc);
    res.count = boost::accumulators::count(acc);
    res.moment = boost::accumulators::moment<2>(acc);

    std::cout << "sum: " << sum << " N: " <<  ctr << " mean: " << res.mean << std::endl;
}

void compute_statistics(std::string inputImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D.nrrd",
                        std::string outfname = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_statistics_new.txt",
                        std::string outfname2 = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_statistics_old.txt",
                        std::string maskImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_someSegmentation.nrrd",
                        std::string pFfile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_rectangle.pf"                        )
{
    ofstream outFile;
    outFile.open(outfname);

    unsigned int timeStep = 0;

    mitk::Image::Pointer inputImage = mitk::IOUtil::LoadImage(inputImageFile);

    mitk::Image::Pointer maskImage;
    maskImage = mitk::IOUtil::LoadImage(maskImageFile);

    std::vector<mitk::BaseData::Pointer> loadedObjects;
    loadedObjects = mitk::IOUtil::Load(pFfile);
    mitk::BaseData::Pointer pf = loadedObjects[0];
    mitk::PlanarFigure::Pointer planarFigure = dynamic_cast<mitk::PlanarFigure*>(pf.GetPointer());

    mitk::ImageStatisticsCalculator::Pointer calculator = mitk::ImageStatisticsCalculator::New();
    mitk::ImageStatisticsCalculator::StatisticsContainer::Pointer result;
    calculator->SetInputImage(inputImage);
    calculator->SetNBinsForHistogramStatistics(100);

    long start_time;

    outFile << "Calculating Statistics on Pic3D" << std::endl << std::endl;

    outFile << "New Image Statistics Calculator" << std::endl;

    start_time = getTimeInMs();
    outFile << "1) unmasked: " << std::endl;
    calculator->SetMask(nullptr);
    result = calculator->GetStatistics(timeStep);
    outFile << result->GetAsString() << std::endl;
    outFile << "new image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

    start_time = getTimeInMs();
    outFile << "2) planarfigure: " << std::endl;
    mitk::PlanarFigureMaskGenerator::Pointer planarFigMaskExtr = mitk::PlanarFigureMaskGenerator::New();
    planarFigMaskExtr->SetPlanarFigure(planarFigure);
    planarFigMaskExtr->SetInputImage(inputImage);
    calculator->SetMask(planarFigMaskExtr.GetPointer());
    result = calculator->GetStatistics(timeStep, 1);
    outFile << result->GetAsString() << std::endl;
    outFile << "new image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

    start_time = getTimeInMs();
    outFile << "3) ignore pixel value mask: " << std::endl;
    mitk::IgnorePixelMaskGenerator::Pointer ignPixVal = mitk::IgnorePixelMaskGenerator::New();
    ignPixVal->SetInputImage(inputImage);
    ignPixVal->SetIgnoredPixelValue(0);
    calculator->SetMask(ignPixVal.GetPointer());
    result = calculator->GetStatistics(timeStep, 1);
    outFile << result->GetAsString() << std::endl;
    outFile << "new image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

    start_time = getTimeInMs();
    outFile << "4) image mask: " << std::endl;
    mitk::ImageMaskGenerator::Pointer binaryImageMaskGen = mitk::ImageMaskGenerator::New();
    binaryImageMaskGen->SetImageMask(maskImage);
    calculator->SetMask(binaryImageMaskGen.GetPointer());
    result = calculator->GetStatistics(timeStep, 1);
    outFile << result->GetAsString() << std::endl;
    outFile << "new image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

    start_time = getTimeInMs();
    outFile << "5) hotspot mask: " << std::endl;
    mitk::HotspotMaskGenerator::Pointer hotSpotMaskGen = mitk::HotspotMaskGenerator::New();
    hotSpotMaskGen->SetInputImage(inputImage);
    hotSpotMaskGen->SetHotspotRadiusInMM(10);
    hotSpotMaskGen->SetTimeStep(0);
    calculator->SetMask(hotSpotMaskGen.GetPointer());
    result = calculator->GetStatistics(timeStep, 1);
    outFile << result->GetAsString() << std::endl;
    outFile << "new image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;
    //mitk::IOUtil::SaveImage(hotSpotMaskGen->GetMask(), "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic2DplusTHotspot.nrrd");

    outFile << "6) all time steps (image mask): " << std::endl;
    if (inputImage->GetTimeSteps() > 1)
    {
        start_time = getTimeInMs();
        for (unsigned int i=0; i < inputImage->GetTimeSteps(); i++)
        {
            outFile << "timestep: " << i << std::endl;
            calculator->SetMask(binaryImageMaskGen.GetPointer());
            result = calculator->GetStatistics(i, 1);
            outFile << result->GetAsString() << std::endl;
            outFile << "new image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;
        }
    }
    else
    {
        outFile << "Input image has only 1 time step!" << std::endl;
    }

    outFile.flush();
    outFile.close();

    // -----------------------------------------------------------------------------------------------------------------------------------------------------------
//    outFile.open(outfname2);

//    std::cout << std::endl << std::endl << "calculating statistics old imgstatcalc: " << std::endl;
//    mitk::ImageStatisticsCalculator::Statistics statisticsStruct;
//    mitk::ImageStatisticsCalculator::Pointer calculator_old;

//    start_time = getTimeInMs();
//    outFile << "1) unmasked: " << std::endl;
//    calculator_old = mitk::ImageStatisticsCalculator::New();
//    calculator_old->SetHistogramBinSize(100);
//    calculator_old->SetImage(inputImage);
//    calculator_old->SetMaskingModeToNone();
//    calculator_old->ComputeStatistics(timeStep);
//    statisticsStruct = calculator_old->GetStatistics(timeStep);
//    outFile << printstats(statisticsStruct) << std::endl;
//    outFile << "old image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

//    start_time = getTimeInMs();
//    outFile << "2) planarFigure: " << std::endl;
//    calculator_old = mitk::ImageStatisticsCalculator::New();
//    calculator_old->SetHistogramBinSize(100);
//    calculator_old->SetImage(inputImage);
//    calculator_old->SetPlanarFigure(planarFigure);
//    calculator_old->SetMaskingModeToPlanarFigure();
//    calculator_old->ComputeStatistics(timeStep);
//    statisticsStruct = calculator_old->GetStatistics(timeStep);
//    outFile << printstats(statisticsStruct) << std::endl;
//    outFile << "old image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

//    start_time = getTimeInMs();
//    outFile << "3) IgnorePixelValue: " << std::endl;
//    calculator_old = mitk::ImageStatisticsCalculator::New();
//    calculator_old->SetHistogramBinSize(100);
//    calculator_old->SetImage(inputImage);
//    calculator_old->SetMaskingModeToNone();
//    calculator_old->SetDoIgnorePixelValue(true);
//    calculator_old->SetIgnorePixelValue(0);
//    calculator_old->ComputeStatistics(timeStep);
//    statisticsStruct = calculator_old->GetStatistics(timeStep);
//    outFile << printstats(statisticsStruct) << std::endl;
//    outFile << "old image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;
//    calculator_old->SetDoIgnorePixelValue(false);

//    start_time = getTimeInMs();
//    outFile << "4) Image Mask: " << std::endl;
//    calculator_old = mitk::ImageStatisticsCalculator::New();
//    calculator_old->SetHistogramBinSize(100);
//    calculator_old->SetImage(inputImage);
//    calculator_old->SetImageMask(maskImage);
//    calculator_old->SetMaskingModeToImage();
//    calculator_old->ComputeStatistics(timeStep);
//    statisticsStruct = calculator_old->GetStatistics(timeStep);
//    outFile << printstats(statisticsStruct) << std::endl;
//    outFile << "old image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;

//    start_time = getTimeInMs();
//    outFile << "5) Hotspot Mask: " << std::endl;
//    calculator_old = mitk::ImageStatisticsCalculator::New();
//    calculator_old->SetHistogramBinSize(100);
//    calculator_old->SetImage(inputImage);
//    calculator_old->SetMaskingModeToNone();
//    calculator_old->SetCalculateHotspot(true);
//    calculator_old->SetHotspotRadiusInMM(10);
//    calculator_old->ComputeStatistics(timeStep);
//    statisticsStruct = calculator_old->GetStatistics(timeStep).GetHotspotStatistics();
//    outFile << printstats(statisticsStruct) << std::endl;
//    outFile << "old image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;
//    calculator_old->SetCalculateHotspot(false);

//    outFile << "6) all time steps (image mask): " << std::endl;
//    if (inputImage->GetTimeSteps() > 1)
//    {
//        start_time = getTimeInMs();
//        calculator_old = mitk::ImageStatisticsCalculator::New();
//        calculator_old->SetHistogramBinSize(100);
//        calculator_old->SetImage(inputImage);
//        calculator_old->SetImageMask(maskImage);
//        calculator_old->SetMaskingModeToImage();
//        for (unsigned int i=0; i < inputImage->GetTimeSteps(); i++)
//        {
//            calculator_old->ComputeStatistics(i);
//            statisticsStruct = calculator_old->GetStatistics(i);
//            outFile << printstats(statisticsStruct) << std::endl;
//            outFile << "old image statistics calculator took: " << getTimeInMs()-start_time << " ms." << std::endl << std::endl;
//        }
//     }
//    else
//    {
//        outFile << "Input image has only 1 time step!" << std::endl;
//    }

//    outFile.flush();
//    outFile.close();
}

int main( int argc, char* argv[] )
{
    std::string inputImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D.nrrd";
    std::string outfname = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_statistics_new.txt";
    std::string outfname2 = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_statistics_old.txt";
    std::string maskImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_someSegmentation.nrrd";
    std::string pFfile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic3D_rectangle.pf";
    compute_statistics(inputImageFile, outfname, outfname2, maskImageFile, pFfile);

    inputImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic2DplusT.nrrd";
    outfname = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic2DplusT_statistics_new.txt";
    outfname2 = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic2DplusT_statistics_old.txt";
    maskImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic2DplusT_someSegmentation.nrrd";
    pFfile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/Pic2DplusT_ellipse.pf";
    compute_statistics(inputImageFile, outfname, outfname2, maskImageFile, pFfile);

    inputImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/leber_ct.pic";
    outfname = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/leber_ct_statistics_new.txt";
    outfname2 = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/leber_ct_statistics_old.txt";
    maskImageFile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/leber_ct_segmentation.nrrd";
    pFfile = "/home/fabian/MITK/MITK_platform_project/bin/MITK-superbuild/MITK-Data/leber_ct_PF.pf";
    compute_statistics(inputImageFile, outfname, outfname2, maskImageFile, pFfile);

    return EXIT_SUCCESS;
}


text:
// Copyright 2015 Cloudera, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "kudu/integration-tests/external_mini_cluster_fs_inspector.h"

#include <algorithm>
#include <boost/foreach.hpp>

#include "kudu/consensus/metadata.pb.h"
#include "kudu/gutil/strings/join.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/fs/fs_manager.h"
#include "kudu/integration-tests/external_mini_cluster.h"
#include "kudu/util/env.h"
#include "kudu/util/monotime.h"
#include "kudu/util/pb_util.h"
#include "kudu/util/status.h"

namespace kudu {
namespace itest {

using std::string;
using std::vector;

using consensus::ConsensusMetadataPB;
using strings::Substitute;
using tablet::TabletDataState;
using tablet::TabletSuperBlockPB;

ExternalMiniClusterFsInspector::ExternalMiniClusterFsInspector(ExternalMiniCluster* cluster)
    : env_(Env::Default()),
      cluster_(CHECK_NOTNULL(cluster)) {
}

ExternalMiniClusterFsInspector::~ExternalMiniClusterFsInspector() {}

Status ExternalMiniClusterFsInspector::ListFilesInDir(const string& path,
                                                      vector<string>* entries) {
  RETURN_NOT_OK(env_->GetChildren(path, entries));
  vector<string>::iterator iter = entries->begin();
  while (iter != entries->end()) {
    if (*iter == "." || *iter == ".." || iter->find(".tmp.") != string::npos) {
      iter = entries->erase(iter);
      continue;
    }
    ++iter;
  }
  return Status::OK();
}

int ExternalMiniClusterFsInspector::CountFilesInDir(const string& path) {
  vector<string> entries;
  Status s = ListFilesInDir(path, &entries);
  if (!s.ok()) return 0;
  return entries.size();
}

int ExternalMiniClusterFsInspector::CountWALSegmentsOnTS(int index) {
  string data_dir = cluster_->tablet_server(index)->data_dir();
  string ts_wal_dir = JoinPathSegments(data_dir, FsManager::kWalDirName);
  vector<string> tablets;
  CHECK_OK(ListFilesInDir(ts_wal_dir, &tablets));
  int total_segments = 0;
  BOOST_FOREACH(const string& tablet, tablets) {
    string tablet_wal_dir = JoinPathSegments(ts_wal_dir, tablet);
    total_segments += CountFilesInDir(tablet_wal_dir);
  }
  return total_segments;
}

vector<string> ExternalMiniClusterFsInspector::ListTabletsOnTS(int index) {
  string data_dir = cluster_->tablet_server(index)->data_dir();
  string meta_dir = JoinPathSegments(data_dir, FsManager::kTabletMetadataDirName);
  vector<string> tablets;
  CHECK_OK(ListFilesInDir(meta_dir, &tablets));
  return tablets;
}

int ExternalMiniClusterFsInspector::CountWALSegmentsForTabletOnTS(int index,
                                                                  const string& tablet_id) {
  string data_dir = cluster_->tablet_server(index)->data_dir();
  string wal_dir = JoinPathSegments(data_dir, FsManager::kWalDirName);
  string tablet_wal_dir = JoinPathSegments(wal_dir, tablet_id);
  if (!env_->FileExists(tablet_wal_dir)) {
    return 0;
  }
  return CountFilesInDir(tablet_wal_dir);
}

bool ExternalMiniClusterFsInspector::DoesConsensusMetaExistForTabletOnTS(int index,
                                                                         const string& tablet_id) {
  ConsensusMetadataPB cmeta_pb;
  Status s = ReadConsensusMetadataOnTS(index, tablet_id, &cmeta_pb);
  return s.ok();
}

int ExternalMiniClusterFsInspector::CountReplicasInMetadataDirs() {
  // Rather than using FsManager's functionality for listing blocks, we just manually
  // list the contents of the metadata directory. This is because we're using an
  // external minicluster, and initializing a new FsManager to point at the running
  // tablet servers isn't easy.
  int count = 0;
  for (int i = 0; i < cluster_->num_tablet_servers(); i++) {
    string data_dir = cluster_->tablet_server(i)->data_dir();
    count += CountFilesInDir(JoinPathSegments(data_dir, FsManager::kTabletMetadataDirName));
  }
  return count;
}

Status ExternalMiniClusterFsInspector::CheckNoDataOnTS(int index) {
  string data_dir = cluster_->tablet_server(index)->data_dir();
  if (CountFilesInDir(JoinPathSegments(data_dir, FsManager::kTabletMetadataDirName)) > 0) {
    return Status::IllegalState("tablet metadata blocks still exist", data_dir);
  }
  if (CountWALSegmentsOnTS(index) > 0) {
    return Status::IllegalState("wals still exist", data_dir);
  }
  if (CountFilesInDir(JoinPathSegments(data_dir, FsManager::kConsensusMetadataDirName)) > 0) {
    return Status::IllegalState("consensus metadata still exists", data_dir);
  }
  return Status::OK();;
}

Status ExternalMiniClusterFsInspector::CheckNoData() {
  for (int i = 0; i < cluster_->num_tablet_servers(); i++) {
    RETURN_NOT_OK(CheckNoDataOnTS(i));
  }
  return Status::OK();;
}

Status ExternalMiniClusterFsInspector::ReadTabletSuperBlockOnTS(int index,
                                                                const string& tablet_id,
                                                                TabletSuperBlockPB* sb) {
  string data_dir = cluster_->tablet_server(index)->data_dir();
  string meta_dir = JoinPathSegments(data_dir, FsManager::kTabletMetadataDirName);
  string superblock_path = JoinPathSegments(meta_dir, tablet_id);
  return pb_util::ReadPBContainerFromPath(env_, superblock_path, sb);
}

Status ExternalMiniClusterFsInspector::ReadConsensusMetadataOnTS(int index,
                                                                 const string& tablet_id,
                                                                 ConsensusMetadataPB* cmeta_pb) {
  string data_dir = cluster_->tablet_server(index)->data_dir();
  string cmeta_dir = JoinPathSegments(data_dir, FsManager::kConsensusMetadataDirName);
  string cmeta_file = JoinPathSegments(cmeta_dir, tablet_id);
  if (!env_->FileExists(cmeta_file)) {
    return Status::NotFound("Consensus metadata file not found", cmeta_file);
  }
  return pb_util::ReadPBContainerFromPath(env_, cmeta_file, cmeta_pb);
}

Status ExternalMiniClusterFsInspector::CheckTabletDataStateOnTS(int index,
                                                                const string& tablet_id,
                                                                TabletDataState state) {
  TabletSuperBlockPB sb;
  RETURN_NOT_OK(ReadTabletSuperBlockOnTS(index, tablet_id, &sb));
  if (PREDICT_FALSE(sb.tablet_data_state() != state)) {
    return Status::IllegalState("Tablet data state != " + TabletDataState_Name(state),
                                TabletDataState_Name(sb.tablet_data_state()));
  }
  return Status::OK();
}

Status ExternalMiniClusterFsInspector::WaitForNoData(const MonoDelta& timeout) {
  MonoTime deadline = MonoTime::Now(MonoTime::FINE);
  deadline.AddDelta(timeout);
  Status s;
  while (true) {
    s = CheckNoData();
    if (s.ok()) return Status::OK();
    if (deadline.ComesBefore(MonoTime::Now(MonoTime::FINE))) {
      break;
    }
    SleepFor(MonoDelta::FromMilliseconds(10));
  }
  return Status::TimedOut("Timed out waiting for no data", s.ToString());
}

Status ExternalMiniClusterFsInspector::WaitForNoDataOnTS(int index, const MonoDelta& timeout) {
  MonoTime deadline = MonoTime::Now(MonoTime::FINE);
  deadline.AddDelta(timeout);
  Status s;
  while (true) {
    s = CheckNoDataOnTS(index);
    if (s.ok()) return Status::OK();
    if (deadline.ComesBefore(MonoTime::Now(MonoTime::FINE))) {
      break;
    }
    SleepFor(MonoDelta::FromMilliseconds(10));
  }
  return Status::TimedOut("Timed out waiting for no data", s.ToString());
}

Status ExternalMiniClusterFsInspector::WaitForMinFilesInTabletWalDirOnTS(int index,
                                                                         const string& tablet_id,
                                                                         int count,
                                                                         const MonoDelta& timeout) {
  int seen = 0;
  MonoTime deadline = MonoTime::Now(MonoTime::FINE);
  deadline.AddDelta(timeout);
  while (true) {
    seen = CountWALSegmentsForTabletOnTS(index, tablet_id);
    if (seen >= count) return Status::OK();
    if (deadline.ComesBefore(MonoTime::Now(MonoTime::FINE))) {
      break;
    }
    SleepFor(MonoDelta::FromMilliseconds(10));
  }
  return Status::TimedOut(Substitute("Timed out waiting for number of WAL segments on tablet $0 "
                                     "on TS $1 to be $2. Found $3",
                                     tablet_id, index, count, seen));
}

Status ExternalMiniClusterFsInspector::WaitForReplicaCount(int expected, const MonoDelta& timeout) {
  Status s;
  MonoTime deadline = MonoTime::Now(MonoTime::FINE);
  deadline.AddDelta(timeout);
  int found;
  while (true) {
    found = CountReplicasInMetadataDirs();
    if (found == expected) return Status::OK();
    if (CountReplicasInMetadataDirs() == expected) return Status::OK();
    if (deadline.ComesBefore(MonoTime::Now(MonoTime::FINE))) {
      break;
    }
    SleepFor(MonoDelta::FromMilliseconds(10));
  }
  return Status::TimedOut(Substitute("Timed out waiting for a total replica count of $0. "
                                     "Found $2 replicas",
                                     expected, found));
}

Status ExternalMiniClusterFsInspector::WaitForTabletDataStateOnTS(int index,
                                                                  const string& tablet_id,
                                                                  TabletDataState expected,
                                                                  const MonoDelta& timeout) {
  MonoTime start = MonoTime::Now(MonoTime::FINE);
  MonoTime deadline = start;
  deadline.AddDelta(timeout);
  Status s;
  while (true) {
    s = CheckTabletDataStateOnTS(index, tablet_id, expected);
    if (s.ok()) return Status::OK();
    if (deadline.ComesBefore(MonoTime::Now(MonoTime::FINE))) break;
    SleepFor(MonoDelta::FromMilliseconds(5));
  }
  return Status::TimedOut(Substitute("Timed out after $0 waiting for tablet data state $1: $2",
                                     MonoTime::Now(MonoTime::FINE).GetDeltaSince(start).ToString(),
                                     TabletDataState_Name(expected), s.ToString()));
}

Status ExternalMiniClusterFsInspector::WaitForFilePatternInTabletWalDirOnTs(
    int ts_index, const string& tablet_id,
    const vector<string>& substrings_required,
    const vector<string>& substrings_disallowed,
    const MonoDelta& timeout) {
  Status s;
  MonoTime deadline = MonoTime::Now(MonoTime::FINE);
  deadline.AddDelta(timeout);

  string data_dir = cluster_->tablet_server(ts_index)->data_dir();
  string ts_wal_dir = JoinPathSegments(data_dir, FsManager::kWalDirName);
  string tablet_wal_dir = JoinPathSegments(ts_wal_dir, tablet_id);

  string error_msg;
  vector<string> entries;
  while (true) {
    Status s = ListFilesInDir(tablet_wal_dir, &entries);
    std::sort(entries.begin(), entries.end());

    error_msg = "";
    bool any_missing_required = false;
    BOOST_FOREACH(const string& required_filter, substrings_required) {
      bool filter_matched = false;
      BOOST_FOREACH(const string& entry, entries) {
        if (entry.find(required_filter) != string::npos) {
          filter_matched = true;
          break;
        }
      }
      if (!filter_matched) {
        any_missing_required = true;
        error_msg += "missing from substrings_required: " + required_filter + "; ";
        break;
      }
    }

    bool any_present_disallowed = false;
    BOOST_FOREACH(const string& entry, entries) {
      if (any_present_disallowed) break;
      BOOST_FOREACH(const string& disallowed_filter, substrings_disallowed) {
        if (entry.find(disallowed_filter) != string::npos) {
          any_present_disallowed = true;
          error_msg += "present from substrings_disallowed: " + entry +
                       " (" + disallowed_filter + "); ";
          break;
        }
      }
    }

    if (!any_missing_required && !any_present_disallowed) {
      return Status::OK();
    }
    if (deadline.ComesBefore(MonoTime::Now(MonoTime::FINE))) {
      break;
    }
    SleepFor(MonoDelta::FromMilliseconds(10));
  }

  return Status::TimedOut(Substitute("Timed out waiting for file pattern on "
                                     "tablet $0 on TS $1 in directory $2",
                                     tablet_id, ts_index, tablet_wal_dir),
                          error_msg + "entries: " + JoinStrings(entries, ", "));
}

} // namespace itest
} // namespace kudu

ext: cc

max_stars_repo_name: kv-zuiwanyuan/kudu

max_issues_repo_name: kv-zuiwanyuan/kudu

max_forks_repo_name: kv-zuiwanyuan/kudu


text:
// Copyright (c) 2022 Fetullah Atas, Norwegian University of Life Sciences
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef VOX_NAV_CONTROL__COMMON_HPP_
#define VOX_NAV_CONTROL__COMMON_HPP_

#include <rclcpp/rclcpp.hpp>
#include <visualization_msgs/msg/marker_array.hpp>
#include <std_msgs/msg/color_rgba.hpp>
#include <nav_msgs/msg/path.hpp>

#include <Eigen/Eigen>
#include <ompl/geometric/PathGeometric.h>
#include <ompl/base/SpaceInformation.h>
#include <ompl/base/spaces/ReedsSheppStateSpace.h>
#include <ompl/base/spaces/DubinsStateSpace.h>
#include <ompl/base/spaces/ReedsSheppStateSpace.h>
#include <ompl/base/ScopedState.h>

#include <vox_nav_utilities/tf_helpers.hpp>

namespace vox_nav_control
{
  namespace common
  {

    enum STATE_ENUM
    {
      kX = 0,
      kY = 1,
      kPsi = 2,
      kV = 3,
    };

    enum INPUT_ENUM
    {
      kacc = 0,
      kdf = 1,
    };

    /**
       * @brief We model obstacles with ellipsoids
       * They are then used in opti stack
       *
       */
    struct Ellipsoid
    {
      Eigen::Vector2f center;
      Eigen::Vector2f axes;
      bool is_dynamic;
      double heading;
    };

    /**
     * @brief a struct to keep states organized
     *
     */
    struct States
    {
      double x;   // X position
      double y;   // Y position
      double psi;   // heading angle
      double v;   // linear velocity
      States()
      : x(0.0),
        y(0.0),
        psi(0.0),
        v(0.0) {}
    };

    /**
     * @brief a struct to keep control inputs organized
     *
     */
    struct ControlInput
    {
      double acc;   // accelration command
      double df;   // steering angle command
      ControlInput()
      : acc(0.0),
        df(0.0) {}
    };

    /**
   * @brief all parameters used by MPC class,
   * user needs to create and reconfigure this
   *
   */
    struct Parameters
    {
      // timesteps in MPC Horizon
      int N;
      // discretization time between timesteps(s)
      double DT;
      // distance from CoG to front axle(m)
      double L_F;
      // distance from CoG to rear axle(m)
      double L_R;
      // min / max velocity constraint(m / s)
      double V_MIN;
      double V_MAX;
      // min / max acceleration constraint(m / s ^ 2)
      double A_MIN;
      double A_MAX;
      // min / max front steer angle constraint(rad)
      double DF_MIN;
      double DF_MAX;
      // min / max jerk constraint(m / s ^ 3)
      double A_DOT_MIN;
      double A_DOT_MAX;
      // min / max front steer angle rate constraint(rad / s)
      double DF_DOT_MIN;
      double DF_DOT_MAX;
      // weights on x, y, psi, and v.
      std::vector<double> Q;
      // weights on jerk and skew rate(steering angle derivative)
      std::vector<double> R;
      // enable/disable debug messages
      bool debug_mode;
      // set this true only if user figured the configration
      bool params_configured;

      // Assign meaningful default values to this parameters
      Parameters()
      : N(10),
        DT(0.1),
        L_F(0.65),
        L_R(0.65),
        V_MIN(-10.0),
        V_MAX(10.0),
        A_MIN(-1.0),
        A_MAX(1.0),
        DF_MIN(-0.5),
        DF_MAX(0.5),
        A_DOT_MIN(-1.0),
        A_DOT_MAX(1.0),
        DF_DOT_MIN(-0.5),
        DF_DOT_MAX(0.5),
        Q({100.0, 100.0, 10.0, 0.1}),
        R({10.0, 10.0}),
        debug_mode(true),
        params_configured(false) {}
    };

    static int nearestStateIndex(
      const nav_msgs::msg::Path & reference_traj,
      const geometry_msgs::msg::PoseStamped & curr_robot_pose)
    {
      int closest_state_index = -1;
      int closest_state_distance = 10000.0;
      for (int i = 0; i < reference_traj.poses.size(); i++) {

        double curr_distance =
          vox_nav_utilities::getEuclidianDistBetweenPoses(reference_traj.poses[i], curr_robot_pose);

        if (curr_distance < closest_state_distance) {
          closest_state_distance = curr_distance;
          closest_state_index = i;
        }
      }
      return closest_state_index;
    }

    static std::vector<States> getLocalInterpolatedReferenceStates(
      const geometry_msgs::msg::PoseStamped & curr_robot_pose,
      const Parameters & mpc_parameters,
      const nav_msgs::msg::Path & reference_traj,
      const double global_plan_look_ahead_distance,
      std::shared_ptr<ompl::base::SpaceInformation> si)
    {
      double robot_roll, robot_pitch, robot_yaw;
      geometry_msgs::msg::PoseStamped front_axle_pose;
      vox_nav_utilities::getRPYfromMsgQuaternion(
        curr_robot_pose.pose.orientation, robot_roll, robot_pitch, robot_yaw);

      front_axle_pose.pose.position.x =
        curr_robot_pose.pose.position.x + mpc_parameters.L_F * std::cos(robot_yaw);
      front_axle_pose.pose.position.y =
        curr_robot_pose.pose.position.y + mpc_parameters.L_F * std::sin(robot_yaw);
      front_axle_pose.pose.position.z = 0;

      // Now lets find nearest trajectory point to robot base
      int nearsest_traj_state_index = nearestStateIndex(reference_traj, front_axle_pose);

      // Auto calculate interpolation steps
      double path_euclidian_length = 0.0;
      for (size_t i = 1; i < reference_traj.poses.size(); i++) {
        path_euclidian_length += vox_nav_utilities::getEuclidianDistBetweenPoses(
          reference_traj.poses[i], reference_traj.poses[i - 1]);
      }

      double interpolation_step_size = path_euclidian_length / reference_traj.poses.size();
      int states_to_see_horizon = global_plan_look_ahead_distance / interpolation_step_size;
      int local_goal_state_index = nearsest_traj_state_index + states_to_see_horizon;
      if (local_goal_state_index >= reference_traj.poses.size() - 1) {
        local_goal_state_index = reference_traj.poses.size() - 1;
      }
      // Define a state space, we basically need this only because we want to use OMPL's
      // geometric path, And then we can interpolate this path
      ompl::geometric::PathGeometric path(si);

      ompl::base::ScopedState<>
      closest_ref_traj_state(si->getStateSpace()),
      ompl_local_goal_state(si->getStateSpace());

      // Feed initial state, which is closest ref trajectory state
      double void_var, yaw;

      if (local_goal_state_index - nearsest_traj_state_index < mpc_parameters.N) {
        // Feed Intermediate state , which is nearest state in ref traj
        vox_nav_utilities::getRPYfromMsgQuaternion(
          curr_robot_pose.pose.orientation, void_var, void_var, yaw);
        closest_ref_traj_state[0] = curr_robot_pose.pose.position.x;
        closest_ref_traj_state[1] = curr_robot_pose.pose.position.y;
        closest_ref_traj_state[2] = yaw;
        path.append(static_cast<ompl::base::State *>(closest_ref_traj_state.get()));
      } else {
        // Feed Intermediate state , which is nearest state in ref traj
        vox_nav_utilities::getRPYfromMsgQuaternion(
          reference_traj.poses[nearsest_traj_state_index].pose.orientation, void_var, void_var,
          yaw);
        closest_ref_traj_state[0] =
          reference_traj.poses[nearsest_traj_state_index].pose.position.x;
        closest_ref_traj_state[1] =
          reference_traj.poses[nearsest_traj_state_index].pose.position.y;
        closest_ref_traj_state[2] = yaw;
        path.append(static_cast<ompl::base::State *>(closest_ref_traj_state.get()));
      }

      // Feed the final state, which the local goal for the current control effort.
      // This is basically the state in the ref trajectory, which is closest to global_plan_look_ahead_distance_
      vox_nav_utilities::getRPYfromMsgQuaternion(
        reference_traj.poses[local_goal_state_index].pose.orientation, void_var, void_var, yaw);
      ompl_local_goal_state[0] = reference_traj.poses[local_goal_state_index].pose.position.x;
      ompl_local_goal_state[1] = reference_traj.poses[local_goal_state_index].pose.position.y;
      ompl_local_goal_state[2] = yaw;
      path.append(static_cast<ompl::base::State *>(ompl_local_goal_state.get()));

      // The local ref traj now contains only 3 states, we will interpolate this states with OMPL
      // The count of states after interpolation must be same as horizon defined for the control problem , hence
      // it should be mpc_parameters_.N
      path.interpolate(mpc_parameters.N);

      // Now the local ref traj is interpolated from current robot state up to state at global look ahead distance
      // Lets fill the native MPC type ref states and return to caller
      std::vector<States> interpolated_reference_states;
      for (std::size_t path_idx = 0; path_idx < path.getStateCount(); path_idx++) {
        // cast the abstract state type to the type we expect
        const ompl::base::ReedsSheppStateSpace::StateType * interpolated_state =
          path.getState(path_idx)->as<ompl::base::ReedsSheppStateSpace::StateType>();
        States curr_interpolated_state;
        curr_interpolated_state.v = mpc_parameters.V_MAX;
        curr_interpolated_state.x = interpolated_state->getX();
        curr_interpolated_state.y = interpolated_state->getY();
        curr_interpolated_state.psi = interpolated_state->getYaw();
        interpolated_reference_states.push_back(curr_interpolated_state);
      }
      return interpolated_reference_states;
    }

    static void publishTrajStates(
      const std::vector<States> & interpolated_reference_states,
      const std_msgs::msg::ColorRGBA & color,
      const std::string & ns,
      const rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr publisher)
    {
      visualization_msgs::msg::MarkerArray marker_array;
      for (int i = 0; i < interpolated_reference_states.size(); i++) {
        visualization_msgs::msg::Marker marker;
        marker.header.frame_id = "map";
        marker.header.stamp = rclcpp::Clock().now();
        marker.ns = ns;
        marker.id = i;
        marker.type = visualization_msgs::msg::Marker::ARROW;
        marker.action = visualization_msgs::msg::Marker::ADD;
        marker.lifetime = rclcpp::Duration::from_seconds(0);
        marker.pose.position.x = interpolated_reference_states[i].x;
        marker.pose.position.y = interpolated_reference_states[i].y;
        marker.pose.position.z = 1.3;
        marker.pose.orientation = vox_nav_utilities::getMsgQuaternionfromRPY(
          0, 0, interpolated_reference_states[i].psi);
        marker.scale.x = 0.25;
        marker.scale.y = 0.1;
        marker.scale.z = 0.1;
        marker.color = color;

        marker_array.markers.push_back(marker);
      }
      publisher->publish(marker_array);
    }
  }  //   namespace common

}  // namespace vox_nav_control

#endif  // VOX_NAV_CONTROL__COMMON_HPP_

ext: hpp


text:
#include <Eigen/Dense>
#include <cstdlib>
#include <iostream>

using namespace std;
using namespace Eigen;

void program_body()
{
  Matrix<double, 2, 1> input;
  input << 9, 2;

  Matrix<double, 3, 2> layer1;
  layer1 << 1, 2, 3, 4, 5, 6;

  auto output = layer1 * input;

  Matrix<double, 3, 1> expected_output;
  expected_output << 13, 35, 57;

  if ( output != expected_output ) {
    throw runtime_error( "test failure" );
  }
}

int main()
{
  try {
    program_body();
    return EXIT_SUCCESS;
  } catch ( const exception& e ) {
    cerr << e.what() << "\n";
    return EXIT_FAILURE;
  }
}

max_stars_repo_name: stanford-stagecast/nnfun

max_issues_repo_name: stanford-stagecast/nnfun

max_forks_repo_name: stanford-stagecast/nnfun


text:
#pragma once
#include <boost/asio.hpp>
#include <thread>
#include <mutex>
#include <functional>
#include <boost/bind.hpp>

namespace cytx {
    namespace net
    {
        class ios_wrapper
        {
        public:
            using io_service_t = boost::asio::io_service;
        private:
            using this_t = ios_wrapper;
            using inter_server_ptr = std::shared_ptr<io_service_t>;
            using work_ptr = std::unique_ptr<io_service_t::work>;
        public:
            ios_wrapper()
                : is_owner_(true)
                , ios_(std::make_shared<io_service_t>())
                , ios_work_(std::make_unique<io_service_t::work>(*ios_))
            {}

            ios_wrapper(io_service_t& ios)
                : is_owner_(false)
                , ios_(inter_server_ptr(&ios, [](auto* ptr) {}))
                , ios_work_(std::make_unique<io_service_t::work>(*ios_))
            {}

            ~ios_wrapper()
            {
                stop();
                ios_work_.reset();
                ios_.reset();
            }

            void start()
            {
                if (is_owner_)
                {
                    ios_run_thread_ = std::thread(boost::bind(&io_service_t::run, ios_));
                }
            }

            void stop()
            {
                if (is_owner_)
                {
                    ios_work_.reset();
                    if (ios_->stopped())
                        ios_->stop();
                    if (ios_run_thread_.joinable())
                        ios_run_thread_.join();
                }
            }

            bool is_owner() const
            {
                return is_owner_;
            }

            io_service_t& service()
            {
                return *ios_;
            }

            operator io_service_t&()
            {
                return service();
            }

        private:
            bool is_owner_;
            inter_server_ptr ios_;
            work_ptr ios_work_;
            std::thread ios_run_thread_;
        };
    }
}

max_stars_repo_name: hbccdf/network-core

max_issues_repo_name: hbccdf/network-core

max_forks_repo_name: hbccdf/network-core


text:
#include <ext/net/http_parser.hpp>
#include <ext/net/http/parse_header.hpp>
#include <boost/test/unit_test.hpp>
#include "test_files.h"

BOOST_AUTO_TEST_CASE(http_parser_response_test)
{
	std::string text;
	LoadTestFile("test-files/post.example.txt", text);

	std::istringstream is(text);
	std::string method, url, body;
	std::tie(method, url, body) = ext::net::parse_http_request(is);

	BOOST_CHECK(method == "POST");
	BOOST_CHECK(url    == "/test/index.html");
	BOOST_CHECK(body   == "licenseID=string&content=string&/paramsXML=string");
}

BOOST_AUTO_TEST_CASE(http_parse_header_test)
{
	using namespace ext::net::http;
	std::string_view text;
	std::string_view value, parstr, parval;

	text = "value1, value2";
	parse_header_value(text, value, parstr);
	BOOST_CHECK_EQUAL(value, "value1");
	BOOST_CHECK_EQUAL(parstr, "");
	parse_header_value(text, value, parstr);
	BOOST_CHECK_EQUAL(value, "value2");
	BOOST_CHECK_EQUAL(parstr, "");

	text = "deflate ; q=0.5 , gzip;q=1";

	parse_header_value(text, value, parstr);
	BOOST_CHECK_EQUAL(value, "deflate");
	BOOST_CHECK_EQUAL(parstr, "q=0.5");
	parse_header_value(text, value, parstr);
	BOOST_CHECK_EQUAL(value, "gzip");
	BOOST_CHECK_EQUAL(parstr, "q=1");

	text = "deflate ; q=0.5 , gzip;q=1";
	BOOST_CHECK(not extract_header_value(text, "def", parstr));
	BOOST_CHECK(extract_header_value(text, "deflate", parstr));
	BOOST_CHECK_EQUAL(parstr, "q=0.5");

	text = "deflate ; q=0.5 , gzip;q=1";
	BOOST_CHECK(extract_header_value(text, "gzip", parstr));
	BOOST_CHECK(extract_header_parameter(parstr, "q", parval));
	BOOST_CHECK_EQUAL(parval, "1");
}

BOOST_AUTO_TEST_CASE(http_parse_query_test)
{
	using namespace ext::net::http;
	std::string_view text;
	std::string_view name, value;

	text = "user=palps&action=doit&treason&=duel";
	parse_query(text, name, value);
	BOOST_CHECK_EQUAL(name, "user");
	BOOST_CHECK_EQUAL(value, "palps");
	parse_query(text, name, value);
	BOOST_CHECK_EQUAL(name, "action");
	BOOST_CHECK_EQUAL(value, "doit");
	parse_query(text, name, value);
	BOOST_CHECK_EQUAL(name, "");
	BOOST_CHECK_EQUAL(value, "treason");
	parse_query(text, name, value);
	BOOST_CHECK_EQUAL(name, "");
	BOOST_CHECK_EQUAL(value, "duel");

	text = "user=palps&action=doit&treason&=duel";
	BOOST_CHECK(extract_query(text, "user", value));
	BOOST_CHECK_EQUAL(value, "palps");
	BOOST_CHECK(extract_query(text, "action", value));
	BOOST_CHECK_EQUAL(value, "doit");
	BOOST_CHECK(extract_query(text, "", value));
	BOOST_CHECK_EQUAL(value, "treason");
}

ext: cpp

max_stars_repo_name: dmlys/netlib

max_issues_repo_name: dmlys/netlib

max_forks_repo_name: dmlys/netlib


text:
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "harmonic.h"
#include "adjacency_matrix.h"
#include "cotmatrix.h"
#include "diag.h"
#include "invert_diag.h"
#include "isdiag.h"
#include "massmatrix.h"
#include "min_quad_with_fixed.h"
#include "speye.h"
#include "sum.h"
#include <Eigen/Sparse>

template <
  typename DerivedV,
  typename DerivedF,
  typename Derivedb,
  typename Derivedbc,
  typename DerivedW>
IGL_INLINE bool igl::harmonic(
  const Eigen::PlainObjectBase<DerivedV> & V,
  const Eigen::PlainObjectBase<DerivedF> & F,
  const Eigen::PlainObjectBase<Derivedb> & b,
  const Eigen::PlainObjectBase<Derivedbc> & bc,
  const int k,
  Eigen::PlainObjectBase<DerivedW> & W)
{
  using namespace Eigen;
  typedef typename DerivedV::Scalar Scalar;
  SparseMatrix<Scalar> L,M;
  cotmatrix(V,F,L);
  massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
  return harmonic(L,M,b,bc,k,W);
}

template <
  typename DerivedF,
  typename Derivedb,
  typename Derivedbc,
  typename DerivedW>
IGL_INLINE bool igl::harmonic(
  const Eigen::PlainObjectBase<DerivedF> & F,
  const Eigen::PlainObjectBase<Derivedb> & b,
  const Eigen::PlainObjectBase<Derivedbc> & bc,
  const int k,
  Eigen::PlainObjectBase<DerivedW> & W)
{
  using namespace Eigen;
  typedef typename Derivedbc::Scalar Scalar;
  SparseMatrix<Scalar> A;
  adjacency_matrix(F,A);
  // sum each row
  SparseVector<Scalar> Asum;
  sum(A,1,Asum);
  // Convert row sums into diagonal of sparse matrix
  SparseMatrix<Scalar> Adiag;
  diag(Asum,Adiag);
  SparseMatrix<Scalar> L = A-Adiag;
  SparseMatrix<Scalar> M;
  speye(L.rows(),M);
  return harmonic(L,M,b,bc,k,W);
}

template <
  typename DerivedL,
  typename DerivedM,
  typename Derivedb,
  typename Derivedbc,
  typename DerivedW>
IGL_INLINE bool igl::harmonic(
  const Eigen::SparseMatrix<DerivedL> & L,
  const Eigen::SparseMatrix<DerivedM> & M,
  const Eigen::PlainObjectBase<Derivedb> & b,
  const Eigen::PlainObjectBase<Derivedbc> & bc,
  const int k,
  Eigen::PlainObjectBase<DerivedW> & W)
{
  const int n = L.rows();
  assert(n == L.cols() && "L must be square");
  assert(n == M.cols() && "M must be same size as L");
  assert(n == M.rows() && "M must be square");
  assert(igl::isdiag(M) && "Mass matrix should be diagonal");

  Eigen::SparseMatrix<DerivedL> Q;
  igl::harmonic(L,M,k,Q);

  typedef DerivedL Scalar;
  min_quad_with_fixed_data<Scalar> data;
  min_quad_with_fixed_precompute(Q,b,Eigen::SparseMatrix<Scalar>(),true,data);
  W.resize(n,bc.cols());
  typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
  const VectorXS B = VectorXS::Zero(n,1);
  for(int w = 0;w<bc.cols();w++)
  {
    const VectorXS bcw = bc.col(w);
    VectorXS Ww;
    if(!min_quad_with_fixed_solve(data,B,bcw,VectorXS(),Ww))
    {
      return false;
    }
    W.col(w) = Ww;
  }
  return true;
}

template <
  typename DerivedL,
  typename DerivedM,
  typename DerivedQ>
IGL_INLINE void igl::harmonic(
  const Eigen::SparseMatrix<DerivedL> & L,
  const Eigen::SparseMatrix<DerivedM> & M,
  const int k,
  Eigen::SparseMatrix<DerivedQ> & Q)
{
  assert(L.rows() == L.cols()&&"L should be square");
  assert(M.rows() == M.cols()&&"M should be square");
  assert(L.rows() == M.rows()&&"L should match M's dimensions");
  Eigen::SparseMatrix<DerivedM> Mi;
  invert_diag(M,Mi);
  Q = -L;
  for(int p = 1;p<k;p++)
  {
    Q = (Q*Mi*-L).eval();
  }
}

template <
  typename DerivedV,
  typename DerivedF,
  typename DerivedQ>
IGL_INLINE void igl::harmonic(
  const Eigen::PlainObjectBase<DerivedV> & V,
  const Eigen::PlainObjectBase<DerivedF> & F,
  const int k,
  Eigen::SparseMatrix<DerivedQ> & Q)
{
  Eigen::SparseMatrix<DerivedQ> L,M;
  cotmatrix(V,F,L);
  massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
  return harmonic(L,M,k,Q);
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template specialization
template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);

template bool igl::harmonic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
template bool igl::harmonic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template bool igl::harmonic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::SparseMatrix<double, 0, int>&);
#endif

max_stars_repo_name: Qt-Widgets/TexGraph

max_issues_repo_name: Qt-Widgets/TexGraph

max_forks_repo_name: Qt-Widgets/TexGraph


text:
#pragma once

// Helpers for the JUCE library :(

#include "ompu/plug/error.hpp"
#include "ompu/component_id.hpp"

#include "JuceHeader.h"

#include <boost/range/iterator_range.hpp>
#include <boost/core/ignore_unused.hpp>

namespace ompu { namespace plug {

inline constexpr juce::uint8 operator""
_u8(unsigned long long v) noexcept
{
    return static_cast<juce::uint8>(v);
}

template<class T>
inline auto make_range(T& v) // must be a valid lvalue, because we are going to make a temporary
{
    using std::begin;
    using std::end;

    return boost::make_iterator_range(begin(v), end(v));
}

}} // ompu

max_stars_repo_name: ompu/ompu

max_issues_repo_name: ompu/ompu

max_forks_repo_name: ompu/ompu


text: #include <boost/hana/fwd/slice.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#pragma once

#include <boost/type_traits/is_same.hpp>

namespace metaSMT {
  namespace type {

    struct Boolean {
      template<typename STREAM>
      friend STREAM & operator<< (STREAM & out, Boolean const & ) \
      {  return (out << "Boolean"); }

    };

      /** equality of Boolean Types **/
      template <typename T>
      bool operator== (Boolean const & , T const & ) \
      {  return boost::is_same<T, Boolean>::value; }

  } /* type */
} /* metaSMT */

max_stars_repo_name: voertler/metaSMT

max_issues_repo_name: voertler/metaSMT

max_forks_repo_name: voertler/metaSMT


text:
/**
 * @file xml_tools.hpp
 * @brief XML工具
 * @note 基于boost的XML解析写入工具
 * @author WT
 * @date 2019-07-26
 */
#pragma once

#include <filesystem>

#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

namespace ytlib {

/**
 * @brief 加载xml文件
 * @param[in] filepath xml文件路径，可以使用相对路径
 * @param[out] pt xml结构root
 */
inline void ReadXmlFile(const std::filesystem::path& filepath, boost::property_tree::ptree& pt) {
  const std::filesystem::path& p = std::filesystem::absolute(filepath);
  boost::property_tree::read_xml(p.string(), pt,
                                 boost::property_tree::xml_parser::trim_whitespace);
}

/**
 * @brief 写入xml文件
 * @param[in] filepath xml文件路径，可以使用相对路径
 * @param[out] pt xml结构root
 */
inline void WriteXmlFile(const std::filesystem::path& filepath, const boost::property_tree::ptree& pt) {
  const std::filesystem::path& p = std::filesystem::absolute(filepath);
  const auto& parent_path = p.parent_path();
  if (std::filesystem::status(parent_path).type() != std::filesystem::file_type::directory)
    std::filesystem::create_directories(parent_path);

  boost::property_tree::write_xml(p.string(), pt,
                                  std::locale(),
                                  boost::property_tree::xml_writer_settings<std::string>(' ', 2));
}

/**
 * @brief 读取kv结构到map<string,string>中
 * @note 读取以下结构到map<string,string>中：
 * @code
<Settings>
  <setting key="key1" value="value1" />
  <setting key="key2" value="value2" />
  <setting key="key3" value="value3" />
</Settings>
 * @endcode
 * @param[in] pt xml结构root
 * @param[out] output_map 输出的map结构
 * @param[in] settings_node 数组节点名称
 * @param[in] setting_node kv节点名称
 * @return 是否写入成功
 */
inline bool ReadXmlSettings(const boost::property_tree::ptree& pt, std::map<std::string, std::string>& output_map,
                            const std::string& settings_node = "Settings",
                            const std::string& setting_node = "setting") {
  using ptreetype = boost::property_tree::ptree;
  boost::optional<const ptreetype&> pt_settings = pt.get_child_optional(settings_node);
  if (!pt_settings) return false;

  for (ptreetype::const_iterator itr = pt_settings->begin(); itr != pt_settings->end(); ++itr) {
    if (itr->first != setting_node) continue;
    output_map.emplace(itr->second.get<std::string>("<xmlattr>.key"), itr->second.get<std::string>("<xmlattr>.value"));
  }
  return true;
}

/**
 * @brief 添加map<string,string>到xml的kv结构中
 * @note 添加map<string,string>到xml的kv结构中：
 * @code
<Settings>
  <setting key="key1" value="value1" />
  <setting key="key2" value="value2" />
  <setting key="key3" value="value3" />
</Settings>
 * @endcode
 * @param[in] input_map map结构
 * @param[out] pt xml结构root
 * @param[in] settings_node 数组节点名称
 * @param[in] setting_node kv节点名称
 */
inline void AddXmlSettings(const std::map<std::string, std::string>& input_map, boost::property_tree::ptree& pt,
                           const std::string& settings_node = "Settings",
                           const std::string& setting_node = "setting") {
  if (input_map.empty()) return;

  using ptreetype = boost::property_tree::ptree;
  ptreetype pt_settings;
  for (const auto& itr : input_map) {
    ptreetype pt_setting;
    pt_setting.put("<xmlattr>.key", itr.first);
    pt_setting.put("<xmlattr>.value", itr.second);
    pt_settings.add_child(setting_node, std::move(pt_setting));
  }
  pt.put_child(settings_node, std::move(pt_settings));
}

}  // namespace ytlib


text:
#include "options.hpp"
#include <boost/program_options.hpp>
#include <libgen.h>

namespace po = boost::program_options;

static char const * const option_help = "help";
static char const * const option_admin = "admin";
static char const * const option_files = "files";

bool options::parse(int argc, const char** argv)
{
    m_program = *argv;

    po::options_description options;

    options.add_options()
        (option_help, "display usage")
        (option_admin, "include administrative messages")
        (option_files, po::value<input_file_collection>());

    po::positional_options_description positional;
    positional.add(option_files, -1);

    po::variables_map variables;
    po::store(po::command_line_parser(argc, argv).options(options).positional(positional).run(), variables);

    if (variables.count(option_help) > 0)
    {
        std::cout << "usage: " << basename(const_cast<char*>(m_program.c_str())) << " [--help] [--admin] [FILE]...\n" // NOLINT(cppcoreguidelines-pro-type-const-cast)
                  << options << std::endl;
        m_help = true;
        return true;
    }

    po::notify(variables);

    m_include_admin_messages = variables.count(option_admin) > 0;

    if (variables.count(option_files) > 0)
    {
        m_input_files = variables[option_files].as<input_file_collection>();
    }

    return true;
}

bool options::help() const
{
    return m_help;
}

bool options::include_admin_messages() const
{
    return m_include_admin_messages;
}

const options::input_file_collection& options::input_files() const
{
    return m_input_files;
}

max_stars_repo_name: GaryHughes/crocofix

max_issues_repo_name: GaryHughes/crocofix

max_forks_repo_name: GaryHughes/crocofix


text:
/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/maybe.hpp>

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/integral.hpp>
#include <boost/hana/monad/laws.hpp>
using namespace boost::hana;

BOOST_HANA_CONSTEXPR_LAMBDA auto f = [](auto x) {
    return just(x + int_<1>);
};

BOOST_HANA_CONSTEXPR_LAMBDA auto g = [](auto x) {
    return just(x * int_<3>);
};

int main() {
    BOOST_HANA_CONSTANT_ASSERT(Monad::laws::check(nothing, int_<1>, f, g));
    BOOST_HANA_CONSTANT_ASSERT(Monad::laws::check(just(int_<1>), int_<1>, f, g));
    BOOST_HANA_CONSTEXPR_ASSERT(Monad::laws::check(just(1), int_<1>, f, g));
}

max_stars_repo_name: rbock/hana

max_issues_repo_name: rbock/hana

max_forks_repo_name: rbock/hana


text:
/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main() {
    using namespace boost::lambda;
    typedef std::istream_iterator<int> in;

    std::for_each( in(std::cin), in(), std::cout << (_1 * 3) << " " );
}

max_stars_repo_name: ghalimi/stdlib

max_issues_repo_name: ghalimi/stdlib

max_forks_repo_name: sthagen/stdlib


text:
#include "stdafx.h"
#include "../Task1/RemoteControl.h"
#include "../Task1/TVSet.h"
#include <sstream>
#include <boost/optional.hpp>

using namespace std;
using boost::optional;
using boost::none;

// Зависимости RemoteControl-а вынесены в родительскую структуру,
// чтобы гарантировать их создание до конструирования самого remote-контрола
struct RemoteControlDependencies
{
	CTVSet tv;
	stringstream input;
	ostringstream output;
};

struct RemoteControlFixture : RemoteControlDependencies
{
	CRemoteControl remoteControl;

	RemoteControlFixture()
		: remoteControl(tv, input, output)
	{
	}

	void VerifyCommandHandling(const string& command, const optional<int> & expectedChannel, const string& expectedOutput)
	{
		input << command;
		BOOST_CHECK(remoteControl.HandleCommand());
		BOOST_CHECK_EQUAL(tv.IsTurnedOn(), expectedChannel.is_initialized());
		BOOST_CHECK_EQUAL(tv.GetChannel(), expectedChannel.get_value_or(0));
		BOOST_CHECK(input.eof());
		BOOST_CHECK_EQUAL(output.str(), expectedOutput);
	}
};

BOOST_FIXTURE_TEST_SUITE(Remote_Control, RemoteControlFixture)

	BOOST_AUTO_TEST_CASE(can_handle_TurnOn_command)
	{
		VerifyCommandHandling("TurnOn", 1, "TV is turned on\n");
	}

	BOOST_AUTO_TEST_CASE(can_turn_off_tv_which_is_on)
	{
		tv.TurnOn();
		VerifyCommandHandling("TurnOff", none, "TV is turned off\n");
	}

BOOST_AUTO_TEST_SUITE_END()


text:
#include "join_hash.hpp"

#include <boost/lexical_cast.hpp>
#include <memory>
#include <numeric>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

#include "join_hash/hash_traits.hpp"
#include "resolve_type.hpp"
#include "scheduler/abstract_task.hpp"
#include "scheduler/current_scheduler.hpp"
#include "scheduler/job_task.hpp"
#include "storage/column_visitable.hpp"
#include "storage/create_iterable_from_column.hpp"
#include "type_cast.hpp"
#include "type_comparison.hpp"
#include "utils/assert.hpp"
#include "utils/cuckoo_hashtable.hpp"
#include "utils/murmur_hash.hpp"
#include "utils/timer.hpp"

namespace opossum {

JoinHash::JoinHash(const std::shared_ptr<const AbstractOperator>& left,
                   const std::shared_ptr<const AbstractOperator>& right, const JoinMode mode,
                   const ColumnIDPair& column_ids, const PredicateCondition predicate_condition,
                   const size_t radix_bits)
    : AbstractJoinOperator(OperatorType::JoinHash, left, right, mode, column_ids, predicate_condition),
      _radix_bits(radix_bits) {
  DebugAssert(predicate_condition == PredicateCondition::Equals, "Operator not supported by Hash Join.");
}

const std::string JoinHash::name() const { return "JoinHash"; }

std::shared_ptr<AbstractOperator> JoinHash::_on_recreate(
    const std::vector<AllParameterVariant>& args, const std::shared_ptr<AbstractOperator>& recreated_input_left,
    const std::shared_ptr<AbstractOperator>& recreated_input_right) const {
  return std::make_shared<JoinHash>(recreated_input_left, recreated_input_right, _mode, _column_ids,
                                    _predicate_condition);
}

std::shared_ptr<const Table> JoinHash::_on_execute() {
  std::shared_ptr<const AbstractOperator> build_operator;
  std::shared_ptr<const AbstractOperator> probe_operator;
  ColumnID build_column_id;
  ColumnID probe_column_id;

  // This is the expected implementation for swapping tables:
  // (1) if left or right outer join, outer relation becomes probe relation (we have to swap only for left outer)
  // (2) for a semi and anti join the inputs are always swapped
  bool inputs_swapped = (_mode == JoinMode::Left || _mode == JoinMode::Anti || _mode == JoinMode::Semi);

  // (3) else the smaller relation will become build relation, the larger probe relation
  if (!inputs_swapped && _input_left->get_output()->row_count() > _input_right->get_output()->row_count()) {
    inputs_swapped = true;
  }

  if (inputs_swapped) {
    // luckily we don't have to swap the operation itself here, because we only support the commutative Equi Join.
    build_operator = _input_right;
    probe_operator = _input_left;
    build_column_id = _column_ids.second;
    probe_column_id = _column_ids.first;
  } else {
    build_operator = _input_left;
    probe_operator = _input_right;
    build_column_id = _column_ids.first;
    probe_column_id = _column_ids.second;
  }

  auto adjusted_column_ids = std::make_pair(build_column_id, probe_column_id);

  auto build_input = build_operator->get_output();
  auto probe_input = probe_operator->get_output();

  _impl = make_unique_by_data_types<AbstractReadOnlyOperatorImpl, JoinHashImpl>(
      build_input->column_data_type(build_column_id), probe_input->column_data_type(probe_column_id), build_operator,
      probe_operator, _mode, adjusted_column_ids, _predicate_condition, inputs_swapped, _radix_bits);
  return _impl->_on_execute();
}

void JoinHash::_on_cleanup() { _impl.reset(); }

// currently using 32bit Murmur
using Hash = uint32_t;

/*
This is how elements of the input relations are saved after materialization.
The original value is used to detect hash collisions.
*/
template <typename T>
struct PartitionedElement {
  PartitionedElement() : row_id(NULL_ROW_ID), partition_hash(0), value(T()) {}
  PartitionedElement(RowID row, Hash hash, T val) : row_id(row), partition_hash(hash), value(val) {}

  RowID row_id;
  Hash partition_hash;
  T value;
};

template <typename T>
using Partition = std::vector<PartitionedElement<T>>;

/*
This struct contains radix-partitioned data in a contiguous buffer,
as well as a list of offsets for each partition.
*/
template <typename T>
struct RadixContainer {
  std::shared_ptr<Partition<T>> elements;
  std::vector<size_t> partition_offsets;
};

/*
Build all the hash tables for the partitions of Left. We parallelize this process for all partitions of Left
*/
template <typename LeftType, typename HashedType>
std::vector<std::optional<HashTable<HashedType>>> build(const RadixContainer<LeftType>& radix_container) {
  /*
  NUMA notes:
  The hashtables for each partition P should also reside on the same node as the two vectors leftP and rightP.
  */
  std::vector<std::optional<HashTable<HashedType>>> hashtables;
  hashtables.resize(radix_container.partition_offsets.size() - 1);

  std::vector<std::shared_ptr<AbstractTask>> jobs;
  jobs.reserve(radix_container.partition_offsets.size() - 1);

  for (size_t current_partition_id = 0; current_partition_id < (radix_container.partition_offsets.size() - 1);
       ++current_partition_id) {
    const auto partition_left_begin = radix_container.partition_offsets[current_partition_id];
    const auto partition_left_end = radix_container.partition_offsets[current_partition_id + 1];
    const auto partition_size = partition_left_end - partition_left_begin;

    // Prune empty partitions, so that we don't have too many empty hash tables
    if (partition_size == 0) {
      continue;
    }

    jobs.emplace_back(std::make_shared<JobTask>([&, partition_left_begin, partition_left_end, current_partition_id,
                                                 partition_size]() {
      auto& partition_left = static_cast<Partition<LeftType>&>(*radix_container.elements);

      auto hashtable = HashTable<HashedType>{partition_size};

      for (size_t partition_offset = partition_left_begin; partition_offset < partition_left_end; ++partition_offset) {
        auto& element = partition_left[partition_offset];

        hashtable.put(type_cast<HashedType>(element.value), element.row_id);
      }

      hashtables[current_partition_id] = std::move(hashtable);
    }));
    jobs.back()->schedule();
  }

  CurrentScheduler::wait_for_tasks(jobs);

  return std::move(hashtables);
}

/*
Hashes the given value into the HashedType that is defined by the current Hash Traits.
Performs a lexical cast first, if necessary.
*/
template <typename OriginalType, typename HashedType>
constexpr uint32_t hash_value(OriginalType& value, const unsigned int seed) {
  // clang-format off
  // doesn't deal with constexpr nicely
  if constexpr(!std::is_same_v<OriginalType, HashedType>) {
    return murmur2<HashedType>(type_cast<HashedType>(value), seed);
  } else {
    return murmur2<HashedType>(value, seed);
  }
  // clang-format on
}

template <typename T, typename HashedType>
std::shared_ptr<Partition<T>> materialize_input(const std::shared_ptr<const Table>& in_table, ColumnID column_id,
                                                std::vector<std::shared_ptr<std::vector<size_t>>>& histograms,
                                                const size_t radix_bits, const unsigned int partitioning_seed,
                                                bool keep_nulls = false) {
  // list of all elements that will be partitioned
  auto elements = std::make_shared<Partition<T>>();
  elements->resize(in_table->row_count());

  // fan-out
  const size_t num_partitions = 1ull << radix_bits;

  // currently, we just do one pass
  size_t pass = 0;
  size_t mask = static_cast<uint32_t>(pow(2, radix_bits * (pass + 1)) - 1);

  auto chunk_offsets = std::vector<size_t>(in_table->chunk_count());

  // fill work queue
  size_t output_offset = 0;
  for (ChunkID chunk_id{0}; chunk_id < in_table->chunk_count(); chunk_id++) {
    auto column = in_table->get_chunk(chunk_id)->get_column(column_id);

    chunk_offsets[chunk_id] = output_offset;
    output_offset += column->size();
  }

  // create histograms per chunk
  histograms = std::vector<std::shared_ptr<std::vector<size_t>>>();
  histograms.resize(chunk_offsets.size());

  std::vector<std::shared_ptr<AbstractTask>> jobs;
  jobs.reserve(in_table->chunk_count());

  for (ChunkID chunk_id{0}; chunk_id < in_table->chunk_count(); ++chunk_id) {
    jobs.emplace_back(std::make_shared<JobTask>([&, chunk_id]() {
      // Get information from work queue
      auto output_offset = chunk_offsets[chunk_id];
      auto column = in_table->get_chunk(chunk_id)->get_column(column_id);
      auto& output = static_cast<Partition<T>&>(*elements);

      // prepare histogram
      histograms[chunk_id] = std::make_shared<std::vector<size_t>>(num_partitions);

      auto& histogram = static_cast<std::vector<size_t>&>(*histograms[chunk_id]);

      auto materialized_chunk = std::vector<std::pair<RowID, T>>();

      // Materialize the chunk
      resolve_column_type<T>(*column, [&, chunk_id, keep_nulls](auto& typed_column) {
        auto iterable = create_iterable_from_column<T>(typed_column);

        iterable.for_each([&, chunk_id, keep_nulls](const auto& value) {
          if (!value.is_null() || keep_nulls) {
            materialized_chunk.emplace_back(RowID{chunk_id, value.chunk_offset()}, value.value());
          } else {
            // We need to add this to avoid gaps in the list of offsets when we iterate later on
            materialized_chunk.emplace_back(NULL_ROW_ID, T{});
          }
        });
      });

      size_t row_id = output_offset;

      /*
      For ReferenceColumns we do not use the RowIDs from the referenced tables.
      Instead, we use the index in the ReferenceColumn itself. This way we can later correctly dereference
      values from different inputs (important for Multi Joins).
      For performance reasons this if statement is around the for loop.
      */
      if (auto ref_column = std::dynamic_pointer_cast<const ReferenceColumn>(column)) {
        // hash and add to the other elements
        ChunkOffset offset = 0;
        for (auto&& elem : materialized_chunk) {
          if (elem.first.chunk_offset != INVALID_CHUNK_OFFSET) {
            uint32_t hashed_value = hash_value<T, HashedType>(elem.second, partitioning_seed);
            output[row_id] = PartitionedElement<T>{RowID{chunk_id, offset}, hashed_value, elem.second};

            const Hash radix = (output[row_id].partition_hash >> (32 - radix_bits * (pass + 1))) & mask;
            histogram[radix]++;

            row_id++;
          }

          offset++;
        }
      } else {
        // hash and add to the other elements
        for (auto&& elem : materialized_chunk) {
          if (elem.first.chunk_offset == INVALID_CHUNK_OFFSET) continue;

          uint32_t hashed_value = hash_value<T, HashedType>(elem.second, partitioning_seed);
          output[row_id] = PartitionedElement<T>{elem.first, hashed_value, elem.second};

          const Hash radix = (output[row_id].partition_hash >> (32 - radix_bits * (pass + 1))) & mask;
          histogram[radix]++;

          row_id++;
        }
      }
    }));
    jobs.back()->schedule();
  }

  CurrentScheduler::wait_for_tasks(jobs);

  return elements;
}

template <typename T>
RadixContainer<T> partition_radix_parallel(const std::shared_ptr<Partition<T>>& materialized,
                                           const std::shared_ptr<std::vector<size_t>>& chunk_offsets,
                                           std::vector<std::shared_ptr<std::vector<size_t>>>& histograms,
                                           const size_t radix_bits, bool keep_nulls = false) {
  // fan-out
  const size_t num_partitions = 1ull << radix_bits;

  // currently, we just do one pass
  size_t pass = 0;
  size_t mask = static_cast<uint32_t>(pow(2, radix_bits * (pass + 1)) - 1);

  // allocate new (shared) output
  auto output = std::make_shared<Partition<T>>();
  output->resize(materialized->size());

  auto& offsets = static_cast<std::vector<size_t>&>(*chunk_offsets);

  RadixContainer<T> radix_output;
  radix_output.elements = output;
  radix_output.partition_offsets.resize(num_partitions + 1);

  // use histograms to calculate partition offsets
  size_t offset = 0;
  std::vector<std::vector<size_t>> output_offsets_by_chunk(offsets.size(), std::vector<size_t>(num_partitions));
  for (size_t partition_id = 0; partition_id < num_partitions; ++partition_id) {
    radix_output.partition_offsets[partition_id] = offset;
    for (ChunkID chunk_id{0}; chunk_id < offsets.size(); ++chunk_id) {
      output_offsets_by_chunk[chunk_id][partition_id] = offset;
      offset += (*histograms[chunk_id])[partition_id];
    }
  }
  radix_output.partition_offsets[num_partitions] = offset;

  std::vector<std::shared_ptr<AbstractTask>> jobs;
  jobs.reserve(offsets.size());

  for (ChunkID chunk_id{0}; chunk_id < offsets.size(); ++chunk_id) {
    jobs.emplace_back(std::make_shared<JobTask>([&, chunk_id]() {
      size_t input_offset = offsets[chunk_id];
      auto& output_offsets = output_offsets_by_chunk[chunk_id];

      size_t input_size = 0;
      if (chunk_id < offsets.size() - 1) {
        input_size = offsets[chunk_id + 1] - input_offset;
      } else {
        input_size = materialized->size() - input_offset;
      }

      auto& out = static_cast<Partition<T>&>(*output);
      for (size_t column_offset = input_offset; column_offset < input_offset + input_size; ++column_offset) {
        auto& element = (*materialized)[column_offset];

        if (!keep_nulls && element.row_id.chunk_offset == INVALID_CHUNK_OFFSET) {
          continue;
        }

        const size_t radix = (element.partition_hash >> (32 - radix_bits * (pass + 1))) & mask;

        out[output_offsets[radix]++] = element;
      }
    }));
    jobs.back()->schedule();
  }

  CurrentScheduler::wait_for_tasks(jobs);

  return radix_output;
}

/*
  In the probe phase we take all partitions from the right partition, iterate over them and compare each join candidate
  with the values in the hash table. Since Left and Right are hashed using the same hash function, we can reduce the
  number of hash tables that need to be looked into to just 1.
  */
template <typename RightType, typename HashedType>
void probe(const RadixContainer<RightType>& radix_container,
           const std::vector<std::optional<HashTable<HashedType>>>& hashtables, std::vector<PosList>& pos_list_left,
           std::vector<PosList>& pos_list_right, const JoinMode mode) {
  std::vector<std::shared_ptr<AbstractTask>> jobs;
  jobs.reserve(radix_container.partition_offsets.size() - 1);

  /*
    NUMA notes:
    At this point both input relations are partitioned using radix partitioning.
    Probing will be done per partition for both sides.
    Therefore, inputs for one partition should be located on the same NUMA node,
    and the job that probes that partition should also be on that NUMA node.
    */

  for (size_t current_partition_id = 0; current_partition_id < (radix_container.partition_offsets.size() - 1);
       ++current_partition_id) {
    const auto partition_begin = radix_container.partition_offsets[current_partition_id];
    const auto partition_end = radix_container.partition_offsets[current_partition_id + 1];

    // Skip empty partitions to avoid empty output chunks
    if (partition_begin == partition_end) {
      continue;
    }

    jobs.emplace_back(std::make_shared<JobTask>([&, partition_begin, partition_end, current_partition_id]() {
      // Get information from work queue
      auto& partition = static_cast<Partition<RightType>&>(*radix_container.elements);
      PosList pos_list_left_local;
      PosList pos_list_right_local;

      if (hashtables[current_partition_id]) {
        const auto& hashtable = hashtables.at(current_partition_id);

        for (size_t partition_offset = partition_begin; partition_offset < partition_end; ++partition_offset) {
          auto& row = partition[partition_offset];

          if (mode == JoinMode::Inner && row.row_id.chunk_offset == INVALID_CHUNK_OFFSET) {
            continue;
          }

          // This is where the actual comparison happens. `get` only returns values that match and eliminates hash
          // collisions.
          const auto& matching_rows = hashtable->get(type_cast<HashedType>(row.value));

          if (matching_rows) {
            for (const auto row_id : matching_rows->get()) {
              if (row_id.chunk_offset != INVALID_CHUNK_OFFSET) {
                pos_list_left_local.emplace_back(row_id);
                pos_list_right_local.emplace_back(row.row_id);
              }
            }
            // We assume that the relations have been swapped previously,
            // so that the outer relation is the probing relation.
          } else if (mode == JoinMode::Left || mode == JoinMode::Right) {
            pos_list_left_local.emplace_back(NULL_ROW_ID);
            pos_list_right_local.emplace_back(row.row_id);
          }
        }
      } else if (mode == JoinMode::Left || mode == JoinMode::Right) {
        /*
          We assume that the relations have been swapped previously,
          so that the outer relation is the probing relation.

          Since we did not find a proper hash table,
          we know that there is no match in Left for this partition.
          Hence we are going to write NULL values for each row.
          */

        for (size_t partition_offset = partition_begin; partition_offset < partition_end; ++partition_offset) {
          auto& row = partition[partition_offset];
          pos_list_left_local.emplace_back(NULL_ROW_ID);
          pos_list_right_local.emplace_back(row.row_id);
        }
      }

      if (!pos_list_left_local.empty()) {
        pos_list_left[current_partition_id] = std::move(pos_list_left_local);
        pos_list_right[current_partition_id] = std::move(pos_list_right_local);
      }
    }));
    jobs.back()->schedule();
  }

  CurrentScheduler::wait_for_tasks(jobs);
}

template <typename RightType, typename HashedType>
void probe_semi_anti(const RadixContainer<RightType>& radix_container,
                     const std::vector<std::optional<HashTable<HashedType>>>& hashtables,
                     std::vector<PosList>& pos_lists, const JoinMode mode) {
  std::vector<std::shared_ptr<AbstractTask>> jobs;
  jobs.reserve(radix_container.partition_offsets.size() - 1);

  for (size_t current_partition_id = 0; current_partition_id < (radix_container.partition_offsets.size() - 1);
       ++current_partition_id) {
    const auto partition_begin = radix_container.partition_offsets[current_partition_id];
    const auto partition_end = radix_container.partition_offsets[current_partition_id + 1];

    // Skip empty partitions to avoid empty output chunks
    if (partition_begin == partition_end) {
      continue;
    }

    jobs.emplace_back(std::make_shared<JobTask>([&, partition_begin, partition_end, current_partition_id]() {
      // Get information from work queue
      auto& partition = static_cast<Partition<RightType>&>(*radix_container.elements);

      PosList pos_list_local;

      if (const auto& hashtable = hashtables[current_partition_id]) {
        // Valid hashtable found, so there is at least one match in this partition

        for (size_t partition_offset = partition_begin; partition_offset < partition_end; ++partition_offset) {
          auto& row = partition[partition_offset];

          if (row.row_id.chunk_offset == INVALID_CHUNK_OFFSET) {
            continue;
          }

          const auto& matching_rows = hashtable->get(row.value);

          if ((mode == JoinMode::Semi && matching_rows) || (mode == JoinMode::Anti && !matching_rows)) {
            // Semi: found at least one match for this row -> match
            // Anti: no matching rows found -> match
            pos_list_local.emplace_back(row.row_id);
          }
        }
      } else if (mode == JoinMode::Anti) {
        // no hashtable on other side, but we are in Anti mode
        for (size_t partition_offset = partition_begin; partition_offset < partition_end; ++partition_offset) {
          auto& row = partition[partition_offset];
          pos_list_local.emplace_back(row.row_id);
        }
      }

      if (!pos_list_local.empty()) {
        pos_lists[current_partition_id] = std::move(pos_list_local);
      }
    }));
    jobs.back()->schedule();
  }

  CurrentScheduler::wait_for_tasks(jobs);
}

using PosLists = std::vector<std::shared_ptr<const PosList>>;
using PosListsByColumn = std::vector<std::shared_ptr<PosLists>>;

// See usage in _on_execute() for doc.
PosListsByColumn setup_pos_lists_by_column(const std::shared_ptr<const Table>& input_table) {
  DebugAssert(input_table->type() == TableType::References, "Function only works for reference tables");

  std::map<PosLists, std::shared_ptr<PosLists>> shared_pos_lists_by_pos_lists;

  PosListsByColumn pos_lists_by_column(input_table->column_count());
  auto pos_lists_by_column_it = pos_lists_by_column.begin();

  const auto& input_chunks = input_table->chunks();

  for (ColumnID column_id{0}; column_id < input_table->column_count(); ++column_id) {
    // Get all the input pos lists so that we only have to pointer cast the columns once
    auto pos_list_ptrs = std::make_shared<PosLists>(input_table->chunk_count());
    auto pos_lists_iter = pos_list_ptrs->begin();

    for (ChunkID chunk_id{0}; chunk_id < input_table->chunk_count(); chunk_id++) {
      const auto& ref_column_uncasted = input_chunks[chunk_id]->columns()[column_id];
      const auto ref_column = std::static_pointer_cast<const ReferenceColumn>(ref_column_uncasted);
      *pos_lists_iter = ref_column->pos_list();
      ++pos_lists_iter;
    }

    auto iter = shared_pos_lists_by_pos_lists.emplace(*pos_list_ptrs, pos_list_ptrs).first;

    *pos_lists_by_column_it = iter->second;
    ++pos_lists_by_column_it;
  }

  return pos_lists_by_column;
}

void write_output_columns(ChunkColumns& output_columns, const std::shared_ptr<const Table>& input_table,
                          const PosListsByColumn& input_pos_list_ptrs_sptrs_by_column,
                          std::shared_ptr<PosList> pos_list) {
  std::map<std::shared_ptr<PosLists>, std::shared_ptr<PosList>> output_pos_list_cache;

  // We might use this later, but want to have it outside of the for loop
  std::shared_ptr<Table> dummy_table;

  // Add columns from input table to output chunk
  for (ColumnID column_id{0}; column_id < input_table->column_count(); ++column_id) {
    if (input_table->type() == TableType::References) {
      if (input_table->chunk_count() > 0) {
        std::shared_ptr<BaseColumn> column;
        const auto& input_table_pos_lists = input_pos_list_ptrs_sptrs_by_column[column_id];

        auto iter = output_pos_list_cache.find(input_table_pos_lists);
        if (iter == output_pos_list_cache.end()) {
          // Get the row ids that are referenced
          auto new_pos_list = std::make_shared<PosList>(pos_list->size());
          auto new_pos_list_iter = new_pos_list->begin();
          for (const auto& row : *pos_list) {
            if (row.chunk_offset == INVALID_CHUNK_OFFSET) {
              *new_pos_list_iter = row;
            } else {
              const auto& referenced_pos_list = *(*input_table_pos_lists)[row.chunk_id];
              *new_pos_list_iter = referenced_pos_list[row.chunk_offset];
            }
            ++new_pos_list_iter;
          }

          iter = output_pos_list_cache.emplace(input_table_pos_lists, new_pos_list).first;
        }

        auto ref_col =
            std::static_pointer_cast<const ReferenceColumn>(input_table->get_chunk(ChunkID{0})->get_column(column_id));
        output_columns.push_back(std::make_shared<ReferenceColumn>(ref_col->referenced_table(),
                                                                   ref_col->referenced_column_id(), iter->second));
      } else {
        // If there are no Chunks in the input_table, we can't deduce the Table that input_table is referencING to
        // pos_list will contain only NULL_ROW_IDs anyway, so it doesn't matter which Table the ReferenceColumn that
        // we output is referencing. HACK, but works fine: we create a dummy table and let the ReferenceColumn ref
        // it.
        if (!dummy_table) dummy_table = Table::create_dummy_table(input_table->column_definitions());
        output_columns.push_back(std::make_shared<ReferenceColumn>(dummy_table, column_id, pos_list));
      }
    } else {
      output_columns.push_back(std::make_shared<ReferenceColumn>(input_table, column_id, pos_list));
    }
  }
}

template <typename LeftType, typename RightType>
class JoinHash::JoinHashImpl : public AbstractJoinOperatorImpl {
 public:
  JoinHashImpl(const std::shared_ptr<const AbstractOperator>& left,
               const std::shared_ptr<const AbstractOperator>& right, const JoinMode mode,
               const ColumnIDPair& column_ids, const PredicateCondition predicate_condition, const bool inputs_swapped,
               const size_t radix_bits)
      : _left(left),
        _right(right),
        _mode(mode),
        _column_ids(column_ids),
        _predicate_condition(predicate_condition),
        _inputs_swapped(inputs_swapped),
        _radix_bits(radix_bits) {}

 protected:
  const std::shared_ptr<const AbstractOperator> _left, _right;
  const JoinMode _mode;
  const ColumnIDPair _column_ids;
  const PredicateCondition _predicate_condition;
  const bool _inputs_swapped;

  std::shared_ptr<Table> _output_table;

  const unsigned int _partitioning_seed = 13;
  const size_t _radix_bits;

  // Determine correct type for hashing
  using HashedType = typename JoinHashTraits<LeftType, RightType>::HashType;

  std::shared_ptr<const Table> _on_execute() override {
    /*
    Preparing output table by adding columns from left table.
    */
    TableColumnDefinitions output_column_definitions;

    auto right_in_table = _right->get_output();
    auto left_in_table = _left->get_output();

    if (_inputs_swapped) {
      // Semi/Anti joins are always swapped but do not need the outer relation
      if (_mode == JoinMode::Semi || _mode == JoinMode::Anti) {
        output_column_definitions = right_in_table->column_definitions();
      } else {
        output_column_definitions =
            concatenated(right_in_table->column_definitions(), left_in_table->column_definitions());
      }
    } else {
      output_column_definitions =
          concatenated(left_in_table->column_definitions(), right_in_table->column_definitions());
    }

    _output_table = std::make_shared<Table>(output_column_definitions, TableType::References);

    /*
     * This flag is used in the materialization and probing phases.
     * When dealing with an OUTER join, we need to make sure that we keep the NULL values for the outer relation.
     * In the current implementation, the relation on the right is always the outer relation.
     */
    auto keep_nulls = (_mode == JoinMode::Left || _mode == JoinMode::Right);

    // Pre-partitioning
    // Save chunk offsets into the input relation
    size_t left_chunk_count = left_in_table->chunk_count();
    size_t right_chunk_count = right_in_table->chunk_count();

    auto left_chunk_offsets = std::make_shared<std::vector<size_t>>();
    auto right_chunk_offsets = std::make_shared<std::vector<size_t>>();

    left_chunk_offsets->resize(left_chunk_count);
    right_chunk_offsets->resize(right_chunk_count);

    size_t offset_left = 0;
    for (ChunkID i{0}; i < left_chunk_count; ++i) {
      left_chunk_offsets->operator[](i) = offset_left;
      offset_left += left_in_table->get_chunk(i)->size();
    }

    size_t offset_right = 0;
    for (ChunkID i{0}; i < right_chunk_count; ++i) {
      right_chunk_offsets->operator[](i) = offset_right;
      offset_right += right_in_table->get_chunk(i)->size();
    }

    Timer performance_timer;

    // Materialization phase
    std::vector<std::shared_ptr<std::vector<size_t>>> histograms_left;
    std::vector<std::shared_ptr<std::vector<size_t>>> histograms_right;
    /*
    NUMA notes:
    The materialized vectors don't have any strong NUMA preference because they haven't been partitioned yet.
    However, it would be a good idea to keep each materialized vector on one node if possible.
    This helps choosing a scheduler node for the radix phase (see below).
    */
    // Scheduler note: parallelize this at some point. Currently, the amount of jobs would be too high
    auto materialized_left = materialize_input<LeftType, HashedType>(left_in_table, _column_ids.first, histograms_left,
                                                                     _radix_bits, _partitioning_seed);
    // 'keep_nulls' makes sure that the relation on the right materializes NULL values when executing an OUTER join.
    auto materialized_right = materialize_input<RightType, HashedType>(
        right_in_table, _column_ids.second, histograms_right, _radix_bits, _partitioning_seed, keep_nulls);

    // Radix Partitioning phase
    /*
    NUMA notes:
    If the input vectors (the materialized vectors) reside on a specific node, the partitioning worker for
    this phase should be scheduled on the same node.
    Additionally, the output vectors in this phase are partitioned by a radix key. Therefore it would be good
    to pin the outputs from both sides on the same node for each radix partition. For example, if there are
    only two radix partitions A and B, the partitions leftA and rightA should be on the same node, and the
    partitions leftB and leftB should also be on the same node.
    */
    // Scheduler note: parallelize this at some point. Currently, the amount of jobs would be too high
    auto radix_left =
        partition_radix_parallel<LeftType>(materialized_left, left_chunk_offsets, histograms_left, _radix_bits);
    // 'keep_nulls' makes sure that the relation on the right keeps NULL values when executing an OUTER join.
    auto radix_right = partition_radix_parallel<RightType>(materialized_right, right_chunk_offsets, histograms_right,
                                                           _radix_bits, keep_nulls);

    // Build phase
    auto hashtables = build<LeftType, HashedType>(radix_left);

    // Probe phase
    std::vector<PosList> left_pos_lists;
    std::vector<PosList> right_pos_lists;
    left_pos_lists.resize(radix_right.partition_offsets.size() - 1);
    right_pos_lists.resize(radix_right.partition_offsets.size() - 1);
    /*
    NUMA notes:
    The workers for each radix partition P should be scheduled on the same node as the input data:
    leftP, rightP and hashtableP.
    */
    if (_mode == JoinMode::Semi || _mode == JoinMode::Anti) {
      probe_semi_anti<RightType, HashedType>(radix_right, hashtables, right_pos_lists, _mode);
    } else {
      probe<RightType, HashedType>(radix_right, hashtables, left_pos_lists, right_pos_lists, _mode);
    }

    auto only_output_right_input = _inputs_swapped && (_mode == JoinMode::Semi || _mode == JoinMode::Anti);

    /**
     * Two Caches to avoid redundant reference materialization for Reference input tables. As there might be
     *  quite a lot Partitions (>500 seen), input Chunks (>500 seen), and columns (>50 seen), this speeds up
     *  write_output_chunks a lot.
     *
     * They do two things:
     *      - Make it possible to re-use output pos lists if two columns in the input table have exactly the same
     *          PosLists Chunk by Chunk
     *      - Avoid creating the std::vector<const PosList*> for each Partition over and over again.
     *
     * They hold one entry per column in the table, not per BaseColumn in a single chunk
     */
    PosListsByColumn left_pos_lists_by_column;
    PosListsByColumn right_pos_lists_by_column;

    // left_pos_lists_by_column will only be needed if left is a reference table and being output
    if (left_in_table->type() == TableType::References && !only_output_right_input) {
      left_pos_lists_by_column = setup_pos_lists_by_column(left_in_table);
    }

    // right_pos_lists_by_column will only be needed if right is a reference table
    if (right_in_table->type() == TableType::References) {
      right_pos_lists_by_column = setup_pos_lists_by_column(right_in_table);
    }

    for (size_t partition_id = 0; partition_id < left_pos_lists.size(); ++partition_id) {
      // moving the values into a shared pos list saves us some work in write_output_columns. We know that
      // left_pos_lists and right_pos_lists will not be used again.
      auto left = std::make_shared<PosList>(std::move(left_pos_lists[partition_id]));
      auto right = std::make_shared<PosList>(std::move(right_pos_lists[partition_id]));

      if (left->empty() && right->empty()) {
        continue;
      }

      ChunkColumns output_columns;

      // we need to swap back the inputs, so that the order of the output columns is not harmed
      if (_inputs_swapped) {
        write_output_columns(output_columns, right_in_table, right_pos_lists_by_column, right);

        // Semi/Anti joins are always swapped but do not need the outer relation
        if (!only_output_right_input) {
          write_output_columns(output_columns, left_in_table, left_pos_lists_by_column, left);
        }
      } else {
        write_output_columns(output_columns, left_in_table, left_pos_lists_by_column, left);
        write_output_columns(output_columns, right_in_table, right_pos_lists_by_column, right);
      }

      _output_table->append_chunk(output_columns);
    }

    return _output_table;
  }
};

}  // namespace opossum

max_stars_repo_name: IanJamesMcKay/InMemoryDB

max_issues_repo_name: IanJamesMcKay/InMemoryDB

max_forks_repo_name: IanJamesMcKay/InMemoryDB