aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/types/HasIdentifier.hpp
blob: 74961e3045c28bbff3bf2bc2542e7e1e3dcd0cf1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#pragma once

#include <algorithm>
#include <cassert>
#include <string>
#include <string_view>
#include <ostream>

#include "openvic-simulation/types/Colour.hpp"
#include "openvic-simulation/utility/Getters.hpp"

namespace OpenVic {
   constexpr bool valid_basic_identifier_char(char c) {
      return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_';
   }
   constexpr bool valid_basic_identifier(std::string_view identifier) {
      return std::all_of(identifier.begin(), identifier.end(), valid_basic_identifier_char);
   }
   constexpr std::string_view extract_basic_identifier_prefix(std::string_view identifier) {
      size_t len = 0;
      while (len < identifier.size() && valid_basic_identifier_char(identifier[len])) {
         ++len;
      }
      return { identifier.data(), len };
   }

   /*
    * Base class for objects with a non-empty string identifier. Uniquely named instances of a type derived from this class
    * can be entered into an IdentifierRegistry instance.
    */
   class HasIdentifier {
      /* Not const so it can be moved rather than needing to be copied. */
      std::string PROPERTY(identifier);

   protected:
      HasIdentifier(std::string_view new_identifier): identifier { new_identifier } {
         assert(!identifier.empty());
      }
      HasIdentifier(HasIdentifier const&) = default;

   public:
      HasIdentifier(HasIdentifier&&) = default;
      HasIdentifier& operator=(HasIdentifier const&) = delete;
      HasIdentifier& operator=(HasIdentifier&&) = delete;
   };

   inline std::ostream& operator<<(std::ostream& stream, HasIdentifier const& obj) {
      return stream << obj.get_identifier();
   }
   inline std::ostream& operator<<(std::ostream& stream, HasIdentifier const* obj) {
      return obj != nullptr ? stream << *obj : stream << "<NULL>";
   }

   template<typename T>
   concept HasGetIdentifier = requires(T const& t) {
      { t.get_identifier() } -> std::same_as<std::string_view>;
   };

   /*
    * Base class for objects with associated colour information.
    */
   template<IsColour ColourT>
   class _HasColour {
      const ColourT PROPERTY(colour);

   protected:
      _HasColour(ColourT new_colour, bool cannot_be_null): colour { new_colour } {
         assert(!cannot_be_null || !colour.is_null());
      }
      _HasColour(_HasColour const&) = default;

   public:
      _HasColour(_HasColour&&) = default;
      _HasColour& operator=(_HasColour const&) = delete;
      _HasColour& operator=(_HasColour&&) = delete;
   };

   using HasColour = _HasColour<colour_t>;
   using HasAlphaColour = _HasColour<colour_argb_t>;

   template<typename T>
   concept HasGetColour = requires(T const& t) {
      { t.get_colour() } -> IsColour;
   };

   /*
    * Base class for objects with a unique string identifier and associated colour information.
    */
   template<IsColour ColourT>
   class _HasIdentifierAndColour : public HasIdentifier, public _HasColour<ColourT> {
   protected:
      _HasIdentifierAndColour(std::string_view new_identifier, ColourT new_colour, bool cannot_be_null)
         : HasIdentifier { new_identifier }, _HasColour<ColourT> { new_colour, cannot_be_null } {}
      _HasIdentifierAndColour(_HasIdentifierAndColour const&) = default;

   public:
      _HasIdentifierAndColour(_HasIdentifierAndColour&&) = default;
      _HasIdentifierAndColour& operator=(_HasIdentifierAndColour const&) = delete;
      _HasIdentifierAndColour& operator=(_HasIdentifierAndColour&&) = delete;
   };

   using HasIdentifierAndColour = _HasIdentifierAndColour<colour_t>;
   using HasIdentifierAndAlphaColour = _HasIdentifierAndColour<colour_argb_t>;

   template<std::unsigned_integral T = size_t>
   class HasIndex {
   public:
      using index_t = T;

   private:
      const index_t PROPERTY(index);

   protected:
      HasIndex(index_t new_index) : index { new_index } {}
      HasIndex(HasIndex const&) = default;

   public:
      HasIndex(HasIndex&&) = default;
      HasIndex& operator=(HasIndex const&) = delete;
      HasIndex& operator=(HasIndex&&) = delete;
   };

   template<typename T>
   concept HasGetIndex = requires(T const& t) {
      { t.get_index() } -> std::unsigned_integral;
   };
}