Skip to content

Instantly share code, notes, and snippets.

@BtheDestroyer
Last active January 28, 2022 03:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BtheDestroyer/b79e4f725a0197b093cd20670aa48966 to your computer and use it in GitHub Desktop.
Save BtheDestroyer/b79e4f725a0197b093cd20670aa48966 to your computer and use it in GitHub Desktop.
Formalized Data-Oriented Schema in C++
// Copyright 2022 Bryce Dixon
//
// Permission is hereby granted, free of charge,
// to any person obtaining a copy of this software
// and associated documentation files (the "Software"),
// to deal in the Software without restriction,
// including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
#include <cstdint>
#include <iostream>
#include <tuple>
#include <vector>
template <typename... TTypes>
class schema
{
public:
using table_type = std::tuple<std::vector<TTypes>...>;
using column_id_type = std::size_t;
using entry_id_type = std::size_t;
using entry_data_type = std::tuple<TTypes...>;
constexpr entry_id_type create_entry(const entry_data_type& entry_data) noexcept
{
create_entry_impl(entry_data);
return m_size++;
}
constexpr std::vector<entry_id_type> create_entries(const std::vector<entry_data_type>& entry_data) noexcept
{
std::vector<entry_id_type> r;
r.reserve(entry_data.size());
for (const entry_data_type& data : entry_data)
{
r.emplace_back(create_entry(data));
}
return r;
}
template <typename TColumnType>
[[nodiscard]] constexpr std::vector<TColumnType> get_column() noexcept
{
return std::get<std::vector<TColumnType>>(m_table);
}
template <column_id_type TColumnIndex>
[[nodiscard]] constexpr auto get_column() noexcept
{
return std::get<TColumnIndex>(m_table);
}
[[nodiscard]] constexpr const table_type& get_table() noexcept
{
return m_table;
}
private:
template <column_id_type TIndex = 0>
constexpr void create_entry_impl(const entry_data_type& entry_data) noexcept
{
if constexpr (TIndex < std::tuple_size_v<table_type>)
{
std::get<TIndex>(m_table).emplace_back(std::get<TIndex>(entry_data));
if constexpr (TIndex + 1 < std::tuple_size_v<table_type>)
{
create_entry_impl<TIndex + 1>(entry_data);
}
}
}
entry_id_type m_size;
table_type m_table;
};
// Copyright 2022 Bryce Dixon
//
// Permission is hereby granted, free of charge,
// to any person obtaining a copy of this software
// and associated documentation files (the "Software"),
// to deal in the Software without restriction,
// including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
#include <algorithm>
#include <array>
#include <cstdint>
#include <string_view>
#include "do_schema.hpp"
namespace character
{
class name_type : public std::array<char, 64>
{
public:
constexpr name_type(const std::string_view& name) noexcept
{
std::copy(name.begin(), name.end(), this->begin());
}
constexpr name_type(const char* name) noexcept
{
for (size_type i = 0; i < size(); ++i)
{
if (name[i] == '\0')
{
m_size = i;
return;
}
(*this)[i] = name[i];
}
m_size = size();
}
[[nodiscard]] constexpr operator std::string_view() const noexcept
{
return std::string_view(data(), m_size);
}
private:
size_type m_size;
};
constexpr std::ostream& operator<<(std::ostream& s, const name_type& n) noexcept
{
s << std::string_view(n);
return s;
}
using level_type = std::uint8_t;
struct health_type
{
health_type(const std::uint64_t& v) : v(v) {}
operator std::uint64_t&() { return v; }
operator const std::uint64_t&() const { return v; }
std::uint64_t v;
};
// using health_type = std::uint64_t;
using attack_type = std::uint64_t;
struct defense_type
{
defense_type(const std::uint64_t& v) : v(v) {}
operator std::uint64_t&() { return v; }
operator const std::uint64_t&() const { return v; }
std::uint64_t v;
};
}
using character_schema = schema<
character::name_type,
character::level_type,
character::health_type,
character::attack_type,
character::defense_type>;
namespace character
{
using entry = character_schema::entry_id_type;
}
// Copyright 2022 Bryce Dixon
//
// Permission is hereby granted, free of charge,
// to any person obtaining a copy of this software
// and associated documentation files (the "Software"),
// to deal in the Software without restriction,
// including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
// EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
#include "do_schema.hpp"
#include "do_schema_characters.hpp"
static character_schema c;
int main()
{
c.create_entry({ "Alice", 5, 532, 64, 0 });
c.create_entries({
{ "Bob", 1, 100, 8, 0 },
{ "Cadance", 3, 290, 40, 0 },
{ "David", 15, 7321, 238, 0 },
{ "Emily", 94, 42'532, 3468, 0 }
});
character::entry frank = c.create_entry({ "Frank", 2, 140, 11, 0 });
std::cout << c.get_column<0>()[0] << "\n";
std::cout << c.get_column<3>()[4] << "\n";
std::cout << static_cast<int>(c.get_column<character::defense_type>()[frank]) << "\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment